Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> type in the chain from the given type that contains the given * field or null if it is not found anywhere. */ T getTypeWithProperty(String field, T type); /** * Returns the type of the instance of which this is the prototype or null * if this is not a function prototype. */ T getInstanceFromPrototype(T type); /** * Records that this property could be referenced from any interface that * this type, or any type in its superclass chain, implements. */ void recordInterfaces(T type, T relatedType, DisambiguateProperties<T>.Property p); } /** Implementation of TypeSystem using JSTypes. */ private static class JSTypeSystem implements TypeSystem<JSType> { private final Set<JSType> invalidatingTypes; private JSTypeRegistry registry; public JSTypeSystem(AbstractCompiler compiler) { registry = compiler.getTypeRegistry(); invalidatingTypes = Sets.newHashSet( registry.getNativeType(JSTypeNative.ALL_TYPE), registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE), registry.getNativeType(JSTypeNative.NO_TYPE), registry.getNativeType(JSTypeNative.FUNCTION_PROTOTYPE), registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE), registry.getNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE), registry.getNativeType(JSTypeNative.UNKNOWN_TYPE)); } @Override public void addInvalidatingType(JSType type) { checkState(!type.isUnionType()); invalidatingTypes.add(type); } @Override public StaticScope<JSType> getRootScope() { return null; } @Override public StaticScope<JSType> getFunctionScope(Node node) { return null; } @Override public JSType getType( StaticScope<JSType> scope, Node node, String prop) { if (node.getJSType() == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return node.getJSType(); } @Override public boolean isInvalidatingType(JSType type) { if (type == null || invalidatingTypes.contains(type) || (type.isNamedType

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>() && type.isUnknownType())) { return true; } ObjectType objType = ObjectType.cast(type); return objType != null && !objType.hasReferenceName(); } @Override public ImmutableSet<JSType> getTypesToSkipForType(JSType type) { type = type.restrictByNotNullOrUndefined(); if (type instanceof UnionType) { Set<JSType> types = Sets.newHashSet(type); for (JSType alt : ((UnionType) type).getAlternates()) { types.addAll(getTypesToSkipForTypeNonUnion(type)); } return ImmutableSet.copyOf(types); } return ImmutableSet.copyOf(getTypesToSkipForTypeNonUnion(type)); } private Set<JSType> getTypesToSkipForTypeNonUnion(JSType type) { Set<JSType> types = Sets.newHashSet(); JSType skipType = type; while (skipType != null) { types.add(skipType); ObjectType objSkipType = skipType.toObjectType(); if (objSkipType != null) { skipType = objSkipType.getImplicitPrototype(); } else { break; } } return types; } @Override public boolean isTypeToSkip(JSType type) { return type.isEnumType() || (type.autoboxesTo() != null); } @Override public JSType restrictByNotNullOrUndefined(JSType type) { return type.restrictByNotNullOrUndefined(); } @Override public Iterable<JSType> getTypeAlternatives(JSType type) { if (type.isUnionType()) { return ((UnionType) type).getAlternates(); } else { ObjectType objType = type.toObjectType(); if (objType != null && objType.getConstructor() != null && objType.getConstructor().isInterface()) { List<JSType> list = Lists.newArrayList(); for (FunctionType impl : registry.getDirectImplementors(objType)) { list.add(impl.getInstanceType()); } return list; } else { return null; } } } @Override public ObjectType getTypeWithProperty(String field, JSType type) { if (!(type instanceof ObjectType)) { if (

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>(condition, blindScope, NE); } else { return caseEquality(condition, blindScope, EQ); } case Token.SHEQ: if (outcome) { return caseEquality(condition, blindScope, SHEQ); } else { return caseEquality(condition, blindScope, SHNE); } case Token.SHNE: if (outcome) { return caseEquality(condition, blindScope, SHNE); } else { return caseEquality(condition, blindScope, SHEQ); } case Token.NAME: case Token.GETPROP: return caseNameOrGetProp(condition, blindScope, outcome); case Token.ASSIGN: return firstPreciserScopeKnowingConditionOutcome( condition.getFirstChild(), firstPreciserScopeKnowingConditionOutcome( condition.getFirstChild().getNext(), blindScope, outcome), outcome); case Token.NOT: return firstPreciserScopeKnowingConditionOutcome( condition.getFirstChild(), blindScope, !outcome); case Token.LE: case Token.LT: case Token.GE: case Token.GT: if (outcome) { return caseEquality(condition, blindScope, INEQ); } break; case Token.INSTANCEOF: return caseInstanceOf( condition.getFirstChild(), condition.getLastChild(), blindScope, outcome); case Token.IN: if (outcome && condition.getFirstChild().getType() == Token.STRING) { return caseIn(condition.getLastChild(), condition.getFirstChild().getString(), blindScope); } break; case Token.CASE: Node left = condition.getParent().getFirstChild(); // the switch condition Node right = condition.getFirstChild(); if (outcome) { return caseEquality(left, right, blindScope, SHEQ); } else { return caseEquality(left, right, blindScope, SHNE); } } return nextPreciserScopeKnowingConditionOutcome( condition, blindScope, outcome); } private FlowScope caseEquality(Node condition, FlowScope blindScope, Function<TypePair, TypePair> merging) { return caseEquality(condition.getFirstChild(), condition.getLastChild(), blindScope, merging); } private FlowScope caseEquality

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp.parsing; import com.google.common.collect.ImmutableMap; import com.google.javascript.rhino.jstype.JSTypeRegistry; import java.util.Map; import java.util.Set; /** * Configuration for the AST factory. Should be shared across AST creation * for all files of a compilation process. * * */ public class Config { /** * Central registry for type info. */ final JSTypeRegistry registry; /** * Whether to parse the descriptions of jsdoc comments. */ final boolean parseJsDocDocumentation; /** * Whether we're in ide mode. */ final boolean isIdeMode; /** * Recognized JSDoc annotations, mapped from their name to their internal * representation. */ final Map<String, Annotation> annotationNames; /** * Annotation names. */ Config(JSTypeRegistry registry, Set<String> annotationWhitelist, boolean isIdeMode) { this.registry = registry; this.annotationNames = buildAnnotationNames(annotationWhitelist); this.parseJsDocDocumentation = isIdeMode; this.isIdeMode = isIdeMode; } /** * Create the annotation names from the user-specified * annotation whitelist. */ private static Map<String, Annotation> buildAnnotationNames( Set<String> annotationWhitelist) { ImmutableMap.Builder<String, Annotation> annotationBuilder = ImmutableMap.builder(); annotationBuilder.putAll(Annotation.recognizedAnnotations); for (String unrecognizedAnnotation : annotationWhitelist) { if (!Annotation.recognizedAnnotations.containsKey

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ /** * For functions with function(this: T, ...) and T as arguments, type inference * will set the type of this on a function literal argument to the actual type * of T. * * */ package com.google.javascript.rhino.jstype; public class TemplateType extends ProxyObjectType { private static final long serialVersionUID = 1L; private final String name; TemplateType(JSTypeRegistry registry, String name) { super(

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); this.name = name; } @Override public String getReferenceName() { return name; } @Override public String toString() { return name; } @Override public boolean isTemplateType() { return true; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Boolean type. * */ public class BooleanType extends ValueType { private static final long serialVersionUID = 1L; BooleanType(JSTypeRegistry registry) { super(registry); } @

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Graph.Branch; import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.BooleanLiteralSet; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.JSTypeNative; import com.google.javascript.rhino.jstype.JSTypeRegistry; import com.google.javascript.rhino.jstype.ObjectType; import com.google.javascript.rhino.jstype.StaticSlot; import com.google.javascript.rhino.jstype.UnionType; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Type inference within a script node or a function body, using the data-flow * analysis framework. * * */ class TypeInference extends DataFlowAnalysis.BranchedForwardDataFlowAnalysis<Node, FlowScope> { static final DiagnosticType TEMPLATE_TYPE_NOT_OBJECT_TYPE = DiagnosticType.error( "JSC_TEMPLATE_TYPE_NOT_OBJECT_TYPE", "The template type must be an object type"); static final DiagnosticType TEMPLATE_TYPE_OF_THIS_EXPECTED = DiagnosticType.error( "JSC_TEMPLATE_TYPE_OF_THIS_EXPECTED", "A function type with the template type as the type of this must be a " + "parameter type"); private final AbstractCompiler compiler; private final JSTypeRegistry registry; private final ReverseAbstractInterpreter reverseInterpreter; private final Scope syntacticScope; private final FlowScope functionScope; private final FlowScope bottomScope; /** * Local variables that do not belong to this scope, but are assigned * in this scope. */ private final Multimap<Scope, Var> assignedOuterLocalVars = HashMultimap.create(); /**

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> * Vars that we should not map out type flow for. */ private final Set<String> unflowableVarNames = Sets.newHashSet(); TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg, ReverseAbstractInterpreter reverseInterpreter, Scope functionScope) { this(compiler, cfg, reverseInterpreter, functionScope, ImmutableSet.<Var>of()); } /** * @param unflowableVars Do not do infer flow on the types of these vars. */ // TODO(nicksantos): Create a builder for this class. TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg, ReverseAbstractInterpreter reverseInterpreter, Scope functionScope, Collection<Var> unflowableVars) { super(cfg, new LinkedFlowScope.FlowScopeJoinOp()); this.compiler = compiler; this.registry = compiler.getTypeRegistry(); this.reverseInterpreter = reverseInterpreter; this.syntacticScope = functionScope; this.functionScope = LinkedFlowScope.createEntryLattice(functionScope); for (Var unflowableVar : unflowableVars) { String name = unflowableVar.getName(); if (functionScope.getVar(name) == unflowableVar) { this.unflowableVarNames.add(name); } } Iterator<Var> varIt = functionScope.getVars(); while (varIt.hasNext()) { Var var = varIt.next(); if (this.unflowableVarNames.contains(var.getName())) { continue; } // For each local variable declared with the VAR keyword, the entry // type is VOID. if (var.getParentNode() != null && var.getType() == null && // no declared type var.getParentNode().getType() == Token.VAR && !var.isExtern()) { this.functionScope.inferSlotType( var.getName(), getNativeType(VOID_TYPE)); } } this.bottomScope = LinkedFlowScope.createEntryLattice( new Scope(functionScope.getRootNode(), functionScope.getTypeOfThis())); } @Override FlowScope createInitialEstimateLattice() { return bottomScope; } @Override FlowScope createEntryLattice() { return functionScope

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> Token.ASSIGN_BITOR: case Token.ASSIGN_MUL: case Token.ASSIGN_SUB: case Token.DIV: case Token.MOD: case Token.BITAND: case Token.BITXOR: case Token.BITOR: case Token.MUL: case Token.SUB: case Token.DEC: case Token.INC: case Token.BITNOT: case Token.NUMBER: scope = traverseChildren(n, scope); n.setJSType(getNativeType(NUMBER_TYPE)); break; case Token.LP: case Token.GET_REF: scope = traverse(n.getFirstChild(), scope); n.setJSType(getJSType(n.getFirstChild())); break; case Token.COMMA: scope = traverseChildren(n, scope); n.setJSType(getJSType(n.getLastChild())); break; case Token.STRING: case Token.TYPEOF: scope = traverseChildren(n, scope); n.setJSType(getNativeType(STRING_TYPE)); break; case Token.LT: case Token.LE: case Token.GT: case Token.GE: case Token.NOT: case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: case Token.INSTANCEOF: case Token.IN: case Token.TRUE: case Token.FALSE: scope = traverseChildren(n, scope); n.setJSType(getNativeType(BOOLEAN_TYPE)); break; case Token.GETELEM: scope = traverseGetElem(n, scope); break; case Token.EXPR_RESULT: scope = traverseChildren(n, scope); if (n.getFirstChild().getType() == Token.GETPROP) { ensurePropertyDeclared(n.getFirstChild()); } break; case Token.SWITCH: scope = traverse(n.getFirstChild(), scope); break; case Token.VAR: case Token.RETURN: case Token.THROW: scope = traverseChildren(n, scope); break; case Token.CATCH: scope = traverseCatch(n, scope); break; } if (n.getType() != Token.FUNCTION) {

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> inferred type. // 2) If this isn't an instance object, define it. // 3) If the property of an object is being assigned in the constructor, // define it. // 4) If this is a stub, define it. // 5) Otherwise, do not define the type, but declare it in the registry // so that we can use it for missing property checks. if (objectType.hasProperty(propName) || !objectType.isInstanceType()) { if ("prototype".equals(propName)) { objectType.defineDeclaredProperty(propName, rightType, false); } else { objectType.defineInferredProperty(propName, rightType, false); } } else { if (getprop.getFirstChild().getType() == Token.THIS && getJSType(syntacticScope.getRootNode()).isConstructor()) { objectType.defineInferredProperty(propName, rightType, false); } else { registry.registerPropertyOnType(propName, objectType); } } } } } /** * Defines a declared property if it has not been defined yet. * * This handles the case where a property is declared on an object where * the object type is inferred, and so the object type will not * be known in {@code TypedScopeCreator}. */ private void ensurePropertyDeclared(Node getprop) { ObjectType ownerType = ObjectType.cast( getJSType(getprop.getFirstChild()).restrictByNotNullOrUndefined()); if (ownerType != null) { ensurePropertyDeclaredHelper(getprop, ownerType); } } /** * Declares a property on its owner, if necessary. * @return True if a property was declared. */ private boolean ensurePropertyDeclaredHelper( Node getprop, ObjectType objectType) { String propName = getprop.getLastChild().getString(); String qName = getprop.getQualifiedName(); if (qName != null) { Var var = syntacticScope.getVar(qName); if (var != null && !var.isTypeInferred()) { // Handle normal declarations that could not be addressed earlier. if (propName.equals("prototype") || // Handle prototype declarations that could not be

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> addressed earlier. (!objectType.hasOwnProperty(propName) && (!objectType.isInstanceType() || (var.isExtern() && !objectType.isNativeObjectType())))) { return objectType.defineDeclaredProperty( propName, var.getType(), var.isExtern()); } } } return false; } private FlowScope traverseName(Node n, FlowScope scope) { String varName = n.getString(); Node value = n.getFirstChild(); JSType type = n.getJSType(); if (value != null) { scope = traverse(value, scope); updateScopeForTypeChange(scope, n, n.getJSType() /* could be null */, getJSType(value)); return scope; } else { StaticSlot<JSType> var = scope.getSlot(varName); if (var != null && !(var.isTypeInferred() && unflowableVarNames.contains(varName))) { type = var.getType(); if (type == null) { type = getNativeType(UNKNOWN_TYPE); } } } n.setJSType(type); return scope; } /** Traverse each element of the array. */ private FlowScope traverseArrayLiteral(Node n, FlowScope scope) { scope = traverseChildren(n, scope); n.setJSType(getNativeType(ARRAY_TYPE)); return scope; } private FlowScope traverseObjectLiteral(Node n, FlowScope scope) { if (n.getJSType() != null) { // The node has already been traversed by the data-flow analysis // framework. Don't re-generate the anonymous object as it might lead to // pernicious bugs. return scope; } ObjectType objectType = registry.createAnonymousObjectType(); for (Node name = n.getFirstChild(); name != null; name = name.getNext().getNext()) { Node value = name.getNext(); scope = traverse(name, scope); scope = traverse(value, scope); String memberName = NodeUtil.getStringValue(name); if (memberName != null) { // TODO(nicksantos): We need to fix the parser so that we can // attach JSDoc to the

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> individual elements of object literals. // Right now, this is not possible. objectType.defineInferredProperty(memberName, getJSType(value), false); } else { n.setJSType(getNativeType(UNKNOWN_TYPE)); return scope; } } n.setJSType(objectType); return scope; } private FlowScope traverseAdd(Node n, FlowScope scope) { Node left = n.getFirstChild(); Node right = left.getNext(); scope = traverseChildren(n, scope); JSType leftType = left.getJSType(); JSType rightType = right.getJSType(); JSType type = getNativeType(UNKNOWN_TYPE); if (leftType != null && rightType != null) { boolean leftIsUnknown = leftType.isUnknownType(); boolean rightIsUnknown = rightType.isUnknownType(); if (leftIsUnknown && rightIsUnknown) { type = getNativeType(UNKNOWN_TYPE); } else if ((!leftIsUnknown && leftType.isString()) || (!rightIsUnknown && rightType.isString())) { type = getNativeType(STRING_TYPE); } else if (leftIsUnknown || rightIsUnknown) { type = getNativeType(UNKNOWN_TYPE); } else if (isAddedAsNumber(leftType) && isAddedAsNumber(rightType)) { type = getNativeType(NUMBER_TYPE); } else { type = registry.createUnionType(STRING_TYPE, NUMBER_TYPE); } } n.setJSType(type); if (n.getType() == Token.ASSIGN_ADD) { updateScopeForTypeChange(scope, left, leftType, type); } return scope; } private boolean isAddedAsNumber(JSType type) { return type.isSubtype(registry.createUnionType(VOID_TYPE, NULL_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE, BOOLEAN_TYPE, BOOLEAN_OBJECT_TYPE)); } private FlowScope traverseHook(Node n, FlowScope scope) { Node condition = n.getFirstChild(); Node trueNode = condition.getNext(); Node falseNode = n.getLastChild(); // verify the condition scope = traverse(condition, scope); // reverse abstract interpret

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Parameter = true; // Find the actual type of this argument. if (j + 1 >= n.getChildCount()) { // TypeCheck#visitParameterList will warn so we bail. return; } Node jArgument = n.getChildAtIndex(j + 1); JSType jArgumentType = getJSType(jArgument); if (jArgument.getType() == Token.FUNCTION && jArgumentType instanceof FunctionType) { // If it's an anonymous function, update the type of this // using the actual type of T. FunctionType jArgumentFnType =(FunctionType) jArgumentType; if (jArgumentFnType.getTypeOfThis().isUnknownType()) { // The new type will be picked up when we traverse the inner // function. jArgument.setJSType( new FunctionType( registry, jArgumentFnType.getReferenceName(), jArgumentFnType.getSource(), jArgumentFnType.getParametersNode(), jArgumentFnType.getReturnType(), (ObjectType) iArgumentType)); } } // TODO(user): Add code to TypeCheck to check that the // types of the arguments match. } } j++; } if (!foundTemplateTypeOfThisParameter) { Node source = fnType.getSource(); compiler.report(JSError.make(NodeUtil.getSourceName(source), source, TEMPLATE_TYPE_OF_THIS_EXPECTED)); return; } } } i++; } } private FlowScope traverseNew(Node n, FlowScope scope) { Node constructor = n.getFirstChild(); scope = traverse(constructor, scope); JSType constructorType = constructor.getJSType(); JSType type = null; if (constructorType != null) { constructorType = constructorType.restrictByNotNullOrUndefined(); if (constructorType.isUnknownType()) { type = getNativeType(UNKNOWN_TYPE); } else if (constructorType instanceof FunctionType) { FunctionType ct = (FunctionType) constructorType; if (ct.isConstructor()) { type = ct.getInstanceType(); } } } n.setJSType(type); for (Node arg = constructor.getNext(); arg != null; arg = arg.getNext()) { scope = traverse(arg,

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Type.equals(getNativeType(UNKNOWN_TYPE)) && var != syntacticScope.getSlot(qualifiedName)) { // If the type of this qualified name has been checked in this scope, // then use CHECKED_UNKNOWN_TYPE instead to indicate that. return getNativeType(CHECKED_UNKNOWN_TYPE); } else { return varType; } } } JSType propertyType = null; if (objType != null) { propertyType = objType.findPropertyType(propName); } if ((propertyType == null || propertyType.isUnknownType()) && qualifiedName != null) { // If we find this node in the registry, then we can infer its type. ObjectType regType = ObjectType.cast(registry.getType(qualifiedName)); if (regType != null) { propertyType = regType.getConstructor(); } } return propertyType; } private BooleanOutcomePair traverseOr(Node n, FlowScope scope) { return traverseShortCircuitingBinOp(n, scope, false); } private BooleanOutcomePair traverseShortCircuitingBinOp( Node n, FlowScope scope, boolean condition) { Node left = n.getFirstChild(); Node right = n.getLastChild(); // type the left node BooleanOutcomePair leftLiterals = traverseWithinShortCircuitingBinOp(left, scope.createChildFlowScope()); JSType leftType = left.getJSType(); // reverse abstract interpret the left node to produce the correct // scope in which to verify the right node FlowScope rightScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( left, leftLiterals.getOutcomeFlowScope(left.getType(), condition), condition); // type the right node BooleanOutcomePair rightLiterals = traverseWithinShortCircuitingBinOp( right, rightScope.createChildFlowScope()); JSType rightType = right.getJSType(); JSType type; BooleanOutcomePair literals; if (leftType != null && rightType != null) { leftType = leftType.getRestrictedTypeGivenToBooleanOutcome(!condition); if (leftLiterals.toBooleanOutcomes == BooleanLiteralSet.get(!condition)) { // Use the restricted left type, since the right

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> the entire * expression. */ FlowScope getOutcomeFlowScope(int nodeType, boolean outcome) { if (nodeType == Token.AND && outcome || nodeType == Token.OR && !outcome) { // We know that the whole expression must have executed. return rightScope; } else { return getJoinedFlowScope(); } } } private BooleanOutcomePair newBooleanOutcomePair( JSType jsType, FlowScope flowScope) { if (jsType == null) { return new BooleanOutcomePair( BooleanLiteralSet.BOTH, BooleanLiteralSet.BOTH, flowScope, flowScope); } return new BooleanOutcomePair(jsType.getPossibleToBooleanOutcomes(), registry.getNativeType(BOOLEAN_TYPE).isSubtype(jsType) ? BooleanLiteralSet.BOTH : BooleanLiteralSet.EMPTY, flowScope, flowScope); } private void redeclare(FlowScope scope, String varName, JSType varType) { if (varType == null) { varType = getNativeType(JSTypeNative.UNKNOWN_TYPE); } if (unflowableVarNames.contains(varName)) { return; } scope.inferSlotType(varName, varType); } /** * This method gets the JSType from the Node argument and verifies that it is * present. */ private JSType getJSType(Node n) { JSType jsType = n.getJSType(); if (jsType == null) { // TODO(nicksantos): This branch indicates a compiler bug, not worthy of // halting the compilation but we should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return registry.getNativeType(typeId); } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * String type. * */ public final class StringType extends ValueType { private static final long serialVersionUID = 1L; StringType(JSTypeRegistry registry) { super(registry); }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> */ public final class JSTypeExpression implements Serializable { private static final long serialVersionUID = 1L; /** The root of the AST. */ private final Node root; /** The source name where the type expression appears. */ private final String sourceName; /** The type registry to use for resolution. */ private final JSTypeRegistry registry; public JSTypeExpression(Node root, String sourceName, JSTypeRegistry registry) { this.root = root; this.sourceName = sourceName; this.registry = registry; } /** * Make the given type expression into an optional type expression, * if possible. */ public static JSTypeExpression makeOptionalArg(JSTypeExpression expr) { if (expr.isOptionalArg() || expr.isVarArgs()) { return expr; } else { return new JSTypeExpression( new Node(Token.EQUALS, expr.root), expr.sourceName, expr.registry); } } /** * @return Whether this expression denotes an optional {@code @param}. */ public boolean isOptionalArg() { return root.getType() == Token.EQUALS; } /** * @return Whether this expression denotes a rest args {@code @param}. */ public boolean isVarArgs() { return root.getType() == Token.ELLIPSIS; } /** * Evaluates the type expression into a {@code JSType} object. */ public JSType evaluate(StaticScope<JSType> scope) { JSType type = registry.createFromTypeNodes(root, sourceName, scope); if (root.getBooleanProp(Node.BRACELESS_TYPE)) { type.forgiveUnknownNames(); } return type; } @Override public boolean equals(Object other) { return other instanceof JSTypeExpression && ((JSTypeExpression) other).root.checkTreeEqualsSilent(root); } @Override public int hashCode() { return root.toStringTree().hashCode(); } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * An object type with a declared default index type. * * For example, <code>Object.<number, string></code> can take only numbers as * keys. * * */ final class IndexedType extends ProxyObjectType { private static final long serialVersionUID = 1L; final JSType indexType; IndexedType( JSTypeRegistry registry, ObjectType objectType, JSType index

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Type) { super(registry, objectType); this.indexType = indexType; } @Override public JSType getIndexType() { return indexType; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Native. private final boolean isChecked; UnknownType(JSTypeRegistry registry, boolean isChecked) { super(registry); this.isChecked = isChecked; } @Override public boolean isUnknownType() { return true; } @Override public boolean isCheckedUnknownType() { return isChecked; } @Override public boolean canAssignTo(JSType that) { return true; } @Override public boolean canBeCalled() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public JSType getLeastSupertype(JSType that) { return this; } @Override public JSType getGreatestSubtype(JSType that) { return this; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnknownType(); } @Override public String toString() { return getReferenceName(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { // nothing to define return true; } @Override public ObjectType getImplicitPrototype() { return null; } @Override public int getPropertiesCount() { return Integer.MAX_VALUE; } @Override protected void collectPropertyNames(Set<String> props) { } @Override public JSType getPropertyType(String propertyName) { return this; } @Override public boolean hasProperty(String propertyName) { return true; } @Override public FunctionType getConstructor() { return null; } @Override public String getReferenceName() { return isChecked ? "??" : "?"; } @Override public boolean isPropertyTypeDeclared(String propertyName) { return false; } @

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> { private static final long serialVersionUID = 1L; VoidType(JSTypeRegistry registry) { super(registry); } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isSubtype(this) || that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) { return TRUE; } return FALSE; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isVoidType() { return true; } @Override public String toString() { return "undefined"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseVoidType(); } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> getJSType(n.getLastChild()); if (rightType.isNumber()) { validator.expectNumber( t, n, leftType, "left side of numeric comparison"); } else if (leftType.isNumber()) { validator.expectNumber( t, n, rightType, "right side of numeric comparison"); } else if (leftType.matchesNumberContext() && rightType.matchesNumberContext()) { // OK. } else { // Whether the comparison is numeric will be determined at runtime // each time the expression is evaluated. Regardless, both operands // should match a string context. String message = "left side of comparison"; validator.expectString(t, n, leftType, message); validator.expectNotVoid( t, n, leftType, message, getNativeType(STRING_TYPE)); message = "right side of comparison"; validator.expectString(t, n, rightType, message); validator.expectNotVoid( t, n, rightType, message, getNativeType(STRING_TYPE)); } ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.IN: left = n.getFirstChild(); right = n.getLastChild(); leftType = getJSType(left); rightType = getJSType(right); validator.expectObject(t, n, rightType, "'in' requires an object"); validator.expectString(t, left, leftType, "left side of 'in'"); ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.INSTANCEOF: left = n.getFirstChild(); right = n.getLastChild(); leftType = getJSType(left); rightType = getJSType(right).restrictByNotNullOrUndefined(); validator.expectAnyObject( t, left, leftType, "deterministic instanceof yields false"); validator.expectActualObject( t, right, rightType, "instanceof requires an object"); ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.ASSIGN: visitAssign(t, n); typeable = false; break; case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>getString(), t, n); ensureTyped(t, n); } /** * Make sure that the access of this property is ok. */ private void checkPropertyAccess(JSType childType, String propName, NodeTraversal t, Node n) { ObjectType objectType = childType.dereference(); if (objectType != null) { JSType propType = getJSType(n); if ((!objectType.hasProperty(propName) || objectType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) && propType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) { if (objectType instanceof EnumType) { t.report(n, INEXISTENT_ENUM_ELEMENT, propName); } else if (!objectType.isEmptyType() && reportMissingProperties && !isPropertyTest(n)) { if (!typeRegistry.canPropertyBeDefined(objectType, propName)) { t.report(n, INEXISTENT_PROPERTY, propName, validator.getReadableJSTypeName(n.getFirstChild(), true)); } } } } else { // TODO(nicksantos): might want to flag the access on a non object when // it's impossible to get a property from this type. } } /** * Determines whether this node is testing for the existence of a property. * If true, we will not emit warnings about a missing property. * * @param getProp The GETPROP being tested. */ private boolean isPropertyTest(Node getProp) { Node parent = getProp.getParent(); switch (parent.getType()) { case Token.CALL: return parent.getFirstChild() != getProp && compiler.getCodingConvention().isPropertyTestFunction(parent); case Token.IF: case Token.WHILE: case Token.DO: case Token.FOR: return NodeUtil.getConditionExpression(parent) == getProp; case Token.INSTANCEOF: case Token.TYPEOF: return true; case Token.AND: case Token.HOOK: return parent.getFirstChild() == getProp; } return false; } /** * Visits a GETELEM node. * * @param t The node traversal object that

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>.mozilla.rhino.ast.SwitchStatement; import com.google.javascript.jscomp.mozilla.rhino.ast.ThrowStatement; import com.google.javascript.jscomp.mozilla.rhino.ast.TryStatement; import com.google.javascript.jscomp.mozilla.rhino.ast.UnaryExpression; import com.google.javascript.jscomp.mozilla.rhino.ast.VariableDeclaration; import com.google.javascript.jscomp.mozilla.rhino.ast.VariableInitializer; import com.google.javascript.jscomp.mozilla.rhino.ast.WhileLoop; import com.google.javascript.jscomp.mozilla.rhino.ast.WithStatement; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.ScriptOrFnNode; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.JSTypeRegistry; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; /** * IRFactory transforms the new AST to the old AST. * * */ public class IRFactory { private final String sourceString; private final String sourceName; private final Config config; private final JSTypeRegistry registry; private final ErrorReporter errorReporter; private final TransformDispatcher transformDispatcher; // non-static for thread safety private final Set<String> ALLOWED_DIRECTIVES = Sets.newHashSet("use strict"); // Nodes with JSDoc comments, indexed by the text of the JSDoc comment. // // It's likely that two or more nodes in the same file may have the same // jsdoc comment. In general, that's ok. // // There's one edge case where this might cause problems. If two JSDoc // comments have the same text, and the first JSDoc comment is not attached // to a node, then the second node will get the first JSDoc comment // instead of the second. When this happens, it probably won't cause any // problems. The two JSDoc comments will be exactly the same,

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> except for // their line numbers. Their line numbers will only be exposed for // type name resolution warnings. // // TODO(nicksantos): Change rhino to put the whole Comment object // on the Node. private final Multimap<String, NodeWithJsDoc> nodesWithJsDoc = LinkedHashMultimap.create(); private IRFactory(String sourceString, String sourceName, Config config, ErrorReporter errorReporter) { this.sourceString = sourceString; this.sourceName = sourceName; this.registry = config.registry; this.config = config; this.errorReporter = errorReporter; this.transformDispatcher = new TransformDispatcher(); } public static Node transformTree(AstRoot node, String sourceString, Config config, ErrorReporter errorReporter) { IRFactory irFactory = new IRFactory(sourceString, node.getSourceName(), config, errorReporter); Node irNode = irFactory.transform(node); // @license text gets appended onto the fileLevelJsDocBuilder as found, // and stored straight into the JSDocInfo for the root node. Node.FileLevelJsDocBuilder fileLevelJsDocBuilder = irNode.getJsDocBuilderForNode(); // fileOverviewInfo stores the last bit of fileoverview data we saw. // We only permit one, so throwing away extras is fair. // The fileOverviewInfo gets passed into parseJSDocInfo so that // it can detect when multiple @fileoverviews exist in the same file. JSDocInfo fileOverviewInfo = null; if (node.getComments() != null) { for (Comment comment : node.getComments()) { if (comment.getCommentType() == JSDOC) { JsDocInfoParser jsDocParser = irFactory.createJsDocInfoParser(comment.getValue(), comment.getLineno(), comment.getAbsolutePosition(), fileLevelJsDocBuilder, fileOverviewInfo); if (jsDocParser.getFileOverviewJSDocInfo() != fileOverviewInfo) { fileOverviewInfo = jsDocParser.getFileOverviewJSDocInfo(); } else { JSDocInfo info = jsDocParser.retrieveAndResetParsedJSDocInfo(); if (info != null) { irFactory.attachJs

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> * @param comment The JsDoc comment to parse. * @param lineno The line number of the node this comment is attached to. * @param fileLevelJsDocBuilder The builder for file-level JSDocInfo. * @param fileOverviewInfo The current @fileoverview JSDocInfo, so that the * parser may warn if another @fileoverview is found. May be null. * @return A JSDocInfoParser. Will contain either fileoverview jsdoc, or * normal jsdoc, or no jsdoc (if the method parses to the wrong level). */ private JsDocInfoParser createJsDocInfoParser( String comment, int lineno, int position, Node.FileLevelJsDocBuilder fileLevelJsDocBuilder, JSDocInfo fileOverviewInfo) { // The JsDocInfoParser expects the comment without the initial '/**'. int numOpeningChars = 3; JsDocInfoParser jsdocParser = new JsDocInfoParser( new JsDocTokenStream(comment.substring(numOpeningChars), lineno, position2charno(position) + numOpeningChars), sourceName, config, errorReporter); jsdocParser.setFileLevelJsDocBuilder(fileLevelJsDocBuilder); jsdocParser.setFileOverviewJSDocInfo(fileOverviewInfo); jsdocParser.parse(); return jsdocParser; } /** Attach JSDocInfo to a node, if we can find one. */ private void attachJsDoc(Comment comment, JSDocInfo info) { Collection<NodeWithJsDoc> candidates = nodesWithJsDoc.get(comment.getValue()); if (candidates.isEmpty()) { return; } Iterator<NodeWithJsDoc> candidateIter = candidates.iterator(); Node node = candidateIter.next().node; candidateIter.remove(); node.setJSDocInfo(info); if (info.hasEnumParameterType()) { if (node.getType() == Token.NAME) { registry.identifyEnumName(node.getString()); } else if (node.getType() == Token.VAR && node.getChildCount() == 1) { registry.identifyEnumName( node.getFirstChild().getString()); } else if (node.getType() == Token.ASSIGN

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>) { registry.identifyEnumName( node.getFirstChild().getQualifiedName()); } } } private int position2charno(int position) { int lineIndex = sourceString.lastIndexOf('\n', position); if (lineIndex == -1) { return position; } else { // Subtract one for initial position being 0. return position - lineIndex - 1; } } private Node justTransform(AstNode node) { return transformDispatcher.process(node); } private class TransformDispatcher extends TypeSafeDispatcher<Node> { private Node processGeneric( com.google.javascript.jscomp.mozilla.rhino.Node n) { Node node = new Node(transformTokenType(n.getType())); for (com.google.javascript.jscomp.mozilla.rhino.Node child : n) { node.addChildToBack(transform((AstNode)child)); } return node; } /** * Transforms the given node and then sets its type to Token.STRING if it * was Token.NAME. If its type was already Token.STRING, then quotes it. * Used for properties, as the old AST uses String tokens, while the new one * uses Name tokens for unquoted strings. For example, in * var o = {'a' : 1, b: 2}; * the string 'a' is quoted, while the name b is turned into a string, but * unquoted. */ private Node transformAsString(AstNode n) { Node ret = transform(n); if (ret.getType() == Token.STRING) { ret.putBooleanProp(Node.QUOTED_PROP, true); } else if (ret.getType() == Token.NAME) { ret.setType(Token.STRING); } return ret; } @Override Node processArrayLiteral(ArrayLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = new Node(Token.ARRAYLIT); int skipCount = 0; for (AstNode child : literalNode.getElements()) { Node c = transform(child); if (c.getType() == Token.EMPTY) { skipCount++; }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> case com.google.javascript.jscomp.mozilla.rhino.Token.TRUE: return Token.TRUE; case com.google.javascript.jscomp.mozilla.rhino.Token.SHEQ: return Token.SHEQ; case com.google.javascript.jscomp.mozilla.rhino.Token.SHNE: return Token.SHNE; case com.google.javascript.jscomp.mozilla.rhino.Token.REGEXP: return Token.REGEXP; case com.google.javascript.jscomp.mozilla.rhino.Token.BINDNAME: return Token.BINDNAME; case com.google.javascript.jscomp.mozilla.rhino.Token.THROW: return Token.THROW; case com.google.javascript.jscomp.mozilla.rhino.Token.RETHROW: return Token.RETHROW; case com.google.javascript.jscomp.mozilla.rhino.Token.IN: return Token.IN; case com.google.javascript.jscomp.mozilla.rhino.Token.INSTANCEOF: return Token.INSTANCEOF; case com.google.javascript.jscomp.mozilla.rhino.Token.LOCAL_LOAD: return Token.LOCAL_LOAD; case com.google.javascript.jscomp.mozilla.rhino.Token.GETVAR: return Token.GETVAR; case com.google.javascript.jscomp.mozilla.rhino.Token.SETVAR: return Token.SETVAR; case com.google.javascript.jscomp.mozilla.rhino.Token.CATCH_SCOPE: return Token.CATCH_SCOPE; case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_INIT_KEYS: return Token.ENUM_INIT_KEYS; case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_INIT_VALUES: return Token.ENUM_INIT_VALUES; case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_NEXT: return Token.ENUM_NEXT; case com.google.javascript.jscomp.mozilla.rhino.Token.ENUM_ID: return Token.ENUM_ID; case com.google.javascript.jscomp.mozilla.rhino.Token.THISFN

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.ErrorReporter; /** * Value types (null, void, number, boolean, string). */ abstract class ValueType extends JSType { ValueType(JSTypeRegistry registry) { super(registry); } @Override public boolean isSubtype(JSType that) { return JSType.isSubtype(this, that); } @Override final JS

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/** * The object type represents instances of JavaScript objects such as * {@code Object}, {@code Date}, {@code Function}.<p> * * Objects in JavaScript are unordered collections of properties. * Each property consists of a name, a value and a set of attributes.<p> * * Each instance has an implicit prototype property ({@code [[Prototype]]}) * pointing to an object instance, which itself has an implicit property, thus * forming a chain.<p> * * A class begins life with no name. Later, a name may be provided once it * can be inferred. Note that the name in this case is strictly for * debugging purposes. Looking up type name references goes through the * {@link JSTypeRegistry}.<p> */ class PrototypeObjectType extends ObjectType { private static final long serialVersionUID = 1L; private final String className; private final Map<String, Property> properties; private ObjectType implicitPrototype; private final boolean nativeType; /** * Creates an object type. * * @param className the name of the class. May be {@code null} to * denote an anonymous class. * * @param implicitPrototype the implicit prototype * (a.k.a. {@code [[Prototype]]}) as defined by ECMA-262. If the * implicit prototype is {@code null} the implicit prototype will be * set to the {@link JSTypeNative#OBJECT_TYPE}. */ PrototypeObjectType(JSTypeRegistry registry, String className, ObjectType implicitPrototype) { this(registry, className, implicitPrototype, false); } /** * Creates an object type, allowing specification of the implicit prototype * when creating native objects. */ PrototypeObjectType(JSTypeRegistry registry, String className, ObjectType implicitPrototype, boolean nativeType) { super(registry); this.properties = Maps.newHashMap(); this.className = className; this.nativeType = nativeType; if (nativeType) { this.implicitPrototype = implicitPrototype; } else if (implicitPrototype == null) { this.implicitPrototype = registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } else { this.implicitPrototype = implicitPrototype; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>NativeProperty("toString"); } /** * Given the name of a native object property, checks whether the property is * present on the object and different from the native one. */ private boolean hasOverridenNativeProperty(String propertyName) { if (isNative()) { return false; } JSType propertyType = getPropertyType(propertyName); ObjectType nativeType = this.isFunctionType() ? registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE) : registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE); JSType nativePropertyType = nativeType.getPropertyType(propertyName); return propertyType != nativePropertyType; } @Override public JSType unboxesTo() { if (isStringObjectType()) { return getNativeType(JSTypeNative.STRING_TYPE); } else if (isBooleanObjectType()) { return getNativeType(JSTypeNative.BOOLEAN_TYPE); } else if (isNumberObjectType()) { return getNativeType(JSTypeNative.NUMBER_TYPE); } else { return super.unboxesTo(); } } @Override public boolean matchesObjectContext() { return true; } @Override public boolean canBeCalled() { return isRegexpType(); } /** * Whether this represents a native type (such as Object, Date, * RegExp, etc.). */ boolean isNative() { return nativeType; } @Override public String toString() { return getReferenceName(); } @Override public FunctionType getConstructor() { return null; } @Override public ObjectType getImplicitPrototype() { return implicitPrototype; } /** * This should only be reset on the FunctionPrototypeType, only to fix an * incorrectly established prototype chain due to the user having a mismatch * in super class declaration, and only before properties on that type are * processed. */ void setImplicitPrototype(ObjectType implicitPrototype) { checkState(!hasCachedValues()); this.implicitPrototype = implicitPrototype; } @Override public String getReferenceName() { if (className != null) { return className; } else { return "{...}"; } } @Override public boolean hasReferenceName() { return className != null; }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>SDocInfo; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Object type. * * In JavaScript, all object types have properties, and each of those * properties has a type. Property types may be DECLARED, INFERRED, or * UNKNOWN. * * DECLARED properties have an explicit type annotation, as in: * <code> * /xx @type {number} x/ * Foo.prototype.bar = 1; * </code> * This property may only hold number values, and an assignment to any * other type of value is an error. * * INFERRED properties do not have an explicit type annotation. Rather, * we try to find all the possible types that this property can hold. * <code> * Foo.prototype.bar = 1; * </code> * If the programmer assigns other types of values to this property, * the property will take on the union of all these types. * * UNKNOWN properties are properties on the UNKNOWN type. The UNKNOWN * type has all properties, but we do not know whether they are * declared or inferred. * * */ public abstract class ObjectType extends JSType { private boolean visited; private JSDocInfo docInfo = null; private boolean unknown = true; ObjectType(JSTypeRegistry registry) { super(registry); } /** * Gets the declared default element type. * @see ParameterizedType */ public JSType getParameterType() { return null; } /** * Gets the declared default index type. * @see IndexedType */ public JSType getIndexType() { return null; } /** * Gets the docInfo for this type. */ @Override public JSDocInfo getJSDocInfo() { if (docInfo != null) { return docInfo; } else if (getImplicitPrototype() != null) { return getImplicitPrototype().getJSDocInfo(); } else { return super.getJSDocInfo(); } } /** * Sets the docInfo for this type from the given * {@link JSDocInfo}. The {@code JSDocInfo} may be

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>(); /** * Gets the implicit prototype (a.k.a. the {@code [[Prototype]]} property). */ public abstract ObjectType getImplicitPrototype(); /** * Defines a property whose type is synthesized (i.e. not inferred). * @param propertyName the property's name * @param type the type * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. */ public final boolean defineDeclaredProperty(String propertyName, JSType type, boolean inExterns) { // All property definitions go through this method // or defineInferredProperty. registry.registerPropertyOnType(propertyName, this); return defineProperty(propertyName, type, false, inExterns); } /** * Defines a property whose type is inferred. * @param propertyName the property's name * @param type the type * @param inExterns {@code true} if this property was defined in an externs * file. TightenTypes assumes that any function passed to an externs * property could be called, so setting this incorrectly could result * in live code being removed. */ public final boolean defineInferredProperty(String propertyName, JSType type, boolean inExterns) { // All property definitions go through this method // or defineDeclaredProperty. registry.registerPropertyOnType(propertyName, this); if (hasProperty(propertyName)) { JSType originalType = getPropertyType(propertyName); type = originalType == null ? type : originalType.getLeastSupertype(type); } return defineProperty(propertyName, type, true, inExterns); } /** * Defines a property.<p> * * For clarity, callers should prefer {@link #defineDeclaredProperty} and * {@link #defineInferredProperty}. * * @param propertyName the property's name * @param type the type * @param inferred {@code true} if this property's type is inferred * @param inExterns {@code true} if this property was defined in an externs * file

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> /** * Create a named type based on the reference. */ public NamedType(JSTypeRegistry registry, String reference, String sourceName, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override public void forgiveUnknownNames() { forgiving = true; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return referencedType; } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override public boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equal if they are the same {@code ObjectType} object. * This is complicated by the fact that equals is sometimes called before we * have a chance to resolve the type names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */ @Override public boolean equals(Object that) { if (this == that) { return true; } else if (that instanceof JSType) { ObjectType objType = ObjectType.cast((JSType) that); if (objType != null) { return objType.isNominalType() && reference.equals(objType.getReferenceName()); } } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { // TODO(user): Investigate whether it is really necessary to keep two // different

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> mechanisms for resolving named types, and if so, which order // makes more sense. Now, resolution via registry is first in order to // avoid triggering the warnings built into the resolution via properties. boolean resolved = resolveViaRegistry(t, enclosing); if (detectImplicitPrototypeCycle()) { handleTypeCycle(t); } if (resolved) { super.resolveInternal(t, enclosing); return referencedType; } resolveViaProperties(t, enclosing); if (detectImplicitPrototypeCycle()) { handleTypeCycle(t); } super.resolveInternal(t, enclosing); return referencedType; } /** * Resolves a named type by looking it up in the registry. * @return True if we resolved successfully. */ private boolean resolveViaRegistry( ErrorReporter t, StaticScope<JSType> enclosing) { ObjectType type = ObjectType.cast(registry.getType(reference)); if (type != null) { setReferencedType(type, t, enclosing); return true; } return false; } /** * Resolves a named type by looking up its first component in the scope, and * subsequent components as properties. The scope must have been fully * parsed and a symbol table constructed. */ private void resolveViaProperties(ErrorReporter t, StaticScope<JSType> enclosing) { String[] componentNames = reference.split("\\.", -1); if (componentNames[0].length() == 0) { handleUnresolvedType(t); return; } StaticSlot<JSType> slot = enclosing.getSlot(componentNames[0]); if (slot == null) { handleUnresolvedType(t); return; } // If the first component has a type of 'Unknown', then any type // names using it should be regarded as silently 'Unknown' rather than be // noisy about it. JSType slotType = slot.getType(); if (slotType == null || slotType.isAllType() || slotType.isNoType()) { handleUnresolvedType(t); return; } JSType value = getTypedefType(t, slot, componentNames[0]); if (value == null) { handleUnresolvedType(t);

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> return; } // resolving component by component for (int i = 1; i < componentNames.length; i++) { ObjectType parentClass = ObjectType.cast(value); if (parentClass == null) { handleUnresolvedType(t); return; } if (componentNames[i].length() == 0) { handleUnresolvedType(t); return; } value = parentClass.getPropertyType(componentNames[i]); } // last component of the chain if (value instanceof FunctionType) { FunctionType functionType = (FunctionType)value; if (functionType.isConstructor() || functionType.isInterface()) { setReferencedType(functionType.getInstanceType(), t, enclosing); } else { handleUnresolvedType(t); } } else if (value instanceof EnumType) { setReferencedType(((EnumType) value).getElementsType(), t, enclosing); } else { handleUnresolvedType(t); } } private void setReferencedType(ObjectType type, ErrorReporter t, StaticScope<JSType> enclosing) { referencedType = type; checkEnumElementCycle(t); setResolvedTypeInternal(referencedType); } private void handleTypeCycle(ErrorReporter t) { referencedType = registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); t.warning("Cycle detected in inheritance chain of type " + reference, sourceName, lineno, null, charno); setResolvedTypeInternal(referencedType); } private void checkEnumElementCycle(ErrorReporter t) { if (referencedType instanceof EnumElementType && ((EnumElementType) referencedType).getPrimitiveType() == this) { handleTypeCycle(t); } } // Warns about this type being unresolved iff it's not a forward-declared // type name. private void handleUnresolvedType(ErrorReporter t) { if (!registry.isForwardDeclaredType(reference) && !forgiving && registry.isLastGeneration()) { t.warning("Unknown type " + reference, sourceName, lineno, null, charno); } else { referencedType = registry.getNativeObjectType( JSTypeNative.CHECKED_UNKNOWN_TYPE); } setResolvedType

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> assign {@code x} a type within the {@code f(x)} * call. Since it has no possible type, we assign {@code x} the NoType, * so that {@code f(x)} is legal no matter what the type of {@code f}'s * first argument is. * * * @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a> */ public final class NoType extends NoObjectType { private static final long serialVersionUID = 1L; NoType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNoObjectType() { return false; } @Override public boolean isNoType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public JSType getLeastSupertype(JSType that) { return that; } @Override public JSType getGreatestSubtype(JSType that) { if (that.isUnknownType()) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return this; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.EMPTY; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNoType(); } @Override public String toString() { return "None"; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> collection of elements. Each element * is referenced by its name, and has an {@link EnumElementType} type. * * */ public class EnumType extends PrototypeObjectType { private static final long serialVersionUID = 1L; // the type of the individual elements private EnumElementType elementsType; // the elements' names (they all have the same type) private final Set<String> elements = new HashSet<String>(); /** * Creates an enum type. * * @param name the enum's name * @param elementsType the base type of the individual elements */ EnumType(JSTypeRegistry registry, String name, JSType elementsType) { super(registry, "enum{" + name + "}", null); this.elementsType = new EnumElementType(registry, elementsType, name); } @Override public boolean isEnumType() { return true; } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } /** * Gets the elements defined on this enum. * @return the elements' names defined on this enum. The returned set is * immutable. */ public Set<String> getElements() { return Collections.unmodifiableSet(elements); } public boolean defineElement(String name) { elements.add(name); return defineDeclaredProperty(name, elementsType, false); } /** * Gets the elements' type. */ public EnumElementType getElementsType() { return elementsType; } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = super.testForEquality(that); if (result != null) { return result; } return this.equals(that) ? TRUE : FALSE; } @Override public boolean isSubtype(JSType that) { return that.equals(getNativeType(JSTypeNative.OBJECT_TYPE)) || that.equals(getNativeType(JSTypeNative.OBJECT_PROTOTYPE)) || JSType.isSubtype(this, that); } @Override public String toString() { return getReferenceName(); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Type; ParameterizedType( JSTypeRegistry registry, ObjectType objectType, JSType parameterType) { super(registry, objectType); this.parameterType = parameterType; } @Override public JSType getParameterType() { return parameterType; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> static final long serialVersionUID = 1L; ObjectType referencedType; ProxyObjectType(JSTypeRegistry registry, ObjectType referencedType) { super(registry); this.referencedType = referencedType; } @Override public String getReferenceName() { return referencedType.getReferenceName(); } @Override public boolean hasReferenceName() { return referencedType.hasReferenceName(); } @Override public boolean matchesNumberContext() { return referencedType.matchesNumberContext(); } @Override public boolean matchesStringContext() { return referencedType.matchesStringContext(); } @Override public boolean matchesObjectContext() { return referencedType.matchesObjectContext(); } @Override public boolean canBeCalled() { return referencedType.canBeCalled(); } @Override public boolean isUnknownType() { return referencedType.isUnknownType(); } @Override public boolean isCheckedUnknownType() { return referencedType.isCheckedUnknownType(); } @Override public boolean isNullable() { return referencedType.isNullable(); } @Override public boolean isFunctionPrototypeType() { return referencedType.isFunctionPrototypeType(); } @Override public boolean isEnumType() { return referencedType.isEnumType(); } @Override public boolean isEnumElementType() { return referencedType.isEnumElementType(); } @Override public boolean isConstructor() { return referencedType.isConstructor(); } @Override public boolean isNominalType() { return referencedType.isNominalType(); } @Override public boolean isInstanceType() { return referencedType.isInstanceType(); } @Override public boolean isInterface() { return referencedType.isInterface(); } @Override public boolean isOrdinaryFunction() { return referencedType.isOrdinaryFunction(); } @Override public TernaryValue testForEquality(JSType that) { return referencedType.testForEquality(that); } @Override public boolean isSubtype(JSType that) { return referencedType.isSubtype(that); } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return referencedType.getCtorImplementedInterfaces(); } @Override public boolean canAssignTo(JSType that

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * A builder for the Rhino Node representing Function parameters. * */ public class FunctionParamBuilder { private final JSTypeRegistry registry; private final Node root = new Node(Token.LP); public FunctionParamBuilder(JSTypeRegistry registry) { this.registry =

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> registry; } /** * Add parameters of the given type to the end of the param list. * @return False if this is called after optional params are added. */ public boolean addRequiredParams(JSType ...types) { if (hasOptionalOrVarArgs()) { return false; } for (JSType type : types) { newParameter(type); } return true; } /** * Add optional parameters of the given type to the end of the param list. * @param types Types for each optional parameter. The builder will make them * undefineable. * @return False if this is called after var args are added. */ public boolean addOptionalParams(JSType ...types) { if (hasVarArgs()) { return false; } for (JSType type : types) { newParameter(registry.createOptionalType(type)).setOptionalArg(true); } return true; } /** * Add variable arguments to the end of the parameter list. * @return False if this is called after var args are added. */ public boolean addVarArgs(JSType type) { if (hasVarArgs()) { return false; } // There are two types of variable argument functions: // 1) Programmer-defined var args // 2) Native bottom types that can accept any argument. // For the first one, "undefined" is a valid value for all arguments. // For the second, we do not want to cast it up to undefined. if (!type.isEmptyType()) { type = registry.createOptionalType(type); } newParameter(type).setVarArgs(true); return true; } /** * Copies the parameter specification from the given node. */ public void newParameterFromNode(Node n) { Node newParam = newParameter(n.getJSType()); newParam.setVarArgs(n.isVarArgs()); newParam.setOptionalArg(n.isOptionalArg()); } // Add a parameter to the list with the given type. private Node newParameter(JSType type) { Node paramNode = Node.newString(Token.NAME, ""); paramNode.setJSType(type); root.addChildTo

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>ator and delegate base. */ public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate); /** * @return the name of the delegate superclass. */ public String getDelegateSuperclassName(); /** * Defines the delegate proxy properties. Their types depend on properties of * the delegate base methods. */ public void defineDelegateProxyProperties( JSTypeRegistry registry, Scope scope, Map<ObjectType, ObjectType> delegateProxyMap); /** * Gets the name of the global object. */ public String getGlobalObject(); /** * Whether this CALL function is testing for the existence of a property. */ public boolean isPropertyTestFunction(Node call); /** * Checks if the given method performs a object literal cast, and if it does, * returns information on the cast. By default, always returns null. Meant * to be overridden by subclasses. * * @param t The node traversal. * @param callNode A CALL node. */ public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode); static enum SubclassType { INHERITS, MIXIN } static class SubclassRelationship { final SubclassType type; final Node subclassNode; final Node superclassNode; final String subclassName; final String superclassName; SubclassRelationship(SubclassType type, Node subclassNode, Node superclassNode) { this.type = type; this.subclassNode = subclassNode; this.superclassNode = superclassNode; this.subclassName = subclassNode.getQualifiedName(); this.superclassName = superclassNode.getQualifiedName(); } } /** * Delegates provides a mechanism and structure for identifying where classes * can call out to optional code to augment their functionality. The optional * code is isolated from the base code through the use of a subclass in the * optional code derived from the delegate class in the base code. */ static class DelegateRelationship { /** The subclass in the base code. */ final String delegateBase; /** The class in the base code. */ final String delegator; DelegateRelationship(String delegateBase, String delegator) { this.delegateBase = delegateBase; this.

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> which the * code is specifically designed to work with multiple input types. Because * JavaScript always knows the runtime type of an object value, this is safer * than a C union.<p> * * For instance, values of the union type {@code (String,boolean)} can be of * type {@code String} or of type {@code boolean}. The commutativity of the * statement is captured by making {@code (String,boolean)} and * {@code (boolean,String)} equal.<p> * * The implementation of this class prevents the creation of nested * unions.<p> */ public class UnionType extends JSType { private static final long serialVersionUID = 1L; Set<JSType> alternates; /** * Creates a union type. * * @param alternates the alternates of the union */ UnionType(JSTypeRegistry registry, Set<JSType> alternates) { super(registry); this.alternates = alternates; } /** * Gets the alternate types of this union type. * @return The alternate types of this union type. The returned set is * immutable. */ public Iterable<JSType> getAlternates() { return alternates; } @Override public void forgiveUnknownNames() { for (JSType type : getAlternates()) { type.forgiveUnknownNames(); } } /** * This predicate is used to test whether a given type can appear in a * numeric context, such as an operand of a multiply operator. * * @return true if the type can appear in a numeric context. */ @Override public boolean matchesNumberContext() { // TODO(user): Reverse this logic to make it correct instead of generous. for (JSType t : alternates) { if (t.matchesNumberContext()) { return true; } } return false; } /** * This predicate is used to test whether a given type can appear in a * {@code String} context, such as an operand of a string concat ({@code +}) * operator.<p> * * All types have at least the potential for converting to {@code String}. * When we add externally defined types, such as a browser OM

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> { return true; } canAssign &= t.canAssignTo(that); } return canAssign; } @Override public boolean canBeCalled() { for (JSType t : alternates) { if (!t.canBeCalled()) { return false; } } return true; } @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; for (JSType t : alternates) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } return result; } /** * This predicate determines whether objects of this type can have the * {@code null} value, and therefore can appear in contexts where * {@code null} is expected. * * @return {@code true} for everything but {@code Number} and * {@code Boolean} types. */ @Override public boolean isNullable() { for (JSType t : alternates) { if (t.isNullable()) { return true; } } return false; } @Override public boolean isUnknownType() { for (JSType t : alternates) { if (t.isUnknownType()) { return true; } } return false; } @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType()) { for (JSType alternate : alternates) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } } } return getLeastSupertype(this, that); } JSType meet(JSType that) { UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (JSType alternate : alternates) { if (alternate.isSubtype(that)) { builder

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> * <li>{@code (null, EvalError, URIError)} restricted by * {@code Error} is {@code null}</li> * </ul> * * @param type the supertype of the types to remove from this union type */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { if (t.isUnknownType() || !t.isSubtype(type)) { restricted.addAlternate(t); } } return restricted.build(); } @Override public String toString() { StringBuilder result = new StringBuilder(); boolean firstAlternate = true; result.append("("); SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA); sorted.addAll(alternates); for (JSType t : sorted) { if (!firstAlternate) { result.append("|"); } result.append(t.toString()); firstAlternate = false; } result.append(")"); return result.toString(); } @Override public boolean isSubtype(JSType that) { for (JSType element : alternates) { if (!element.isSubtype(that)) { return false; } } return true; } @Override public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { restricted.addAlternate( element.getRestrictedTypeGivenToBooleanOutcome(outcome)); } return restricted.build(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { BooleanLiteralSet literals = BooleanLiteralSet.EMPTY; for (JSType element : alternates) { literals = literals.union(element.getPossibleToBooleanOutcomes()); if (literals == BooleanLiteralSet.BOTH) { break; } } return literals; } @Override public TypePair getTypesUnderEquality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) {

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> TypePair p = element.getTypesUnderEquality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderShallowInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnionType(this); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); // for circularly defined types. boolean changed = false; ImmutableSet.Builder<JSType> resolvedTypes = ImmutableSet.builder(); for (JSType alternate : alternates) { JSType newAlternate = alternate.resolve(t, scope); changed |= (alternate != newAlternate); resolvedTypes.add(alternate);

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>code> * var x = function() {}; * if (x instanceof Array) { * f(x); * } * </code> * We need to be able to assign {@code x} a type within the {@code f(x)} * call. It has no possible type, but {@code x} would not be legal if f * expected a string. So we assign it the {@code NoObjectType}. * * * * @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a> */ public class NoObjectType extends FunctionType { private static final long serialVersionUID = 1L; /** * Visitor for {@link NoObjectType#getLeastSupertype(JSType)}. */ private final Visitor<JSType> leastSupertypeVisitor = new LeastSupertypeVisitor(); private class LeastSupertypeVisitor implements Visitor<JSType>, Serializable { private static final long serialVersionUID = 1L; public JSType caseNoObjectType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseUnknownType() { return getNativeType(JSTypeNative.UNKNOWN_TYPE); } public JSType caseNoType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseBooleanType() { return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE, JSTypeNative.BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE, JSTypeNative.NULL_TYPE); } public JSType caseNumberType() { return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE, JSTypeNative.NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE, JSTypeNative.STRING_TYPE); } public JSType caseUnionType(UnionType type) { return registry.createUnionType( getNativeType(JS

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>TypeNative.NO_OBJECT_TYPE), type); } public JSType caseAllType() { return getNativeType(JSTypeNative.ALL_TYPE); } public JSType caseVoidType() { return registry.createUnionType(JSTypeNative.NO_OBJECT_TYPE, JSTypeNative.VOID_TYPE); } public JSType caseEnumElementType(EnumElementType type) { JSType primitive = type.getPrimitiveType(); return primitive.isObject() ? primitive : registry.createUnionType( getNativeType(JSTypeNative.NO_OBJECT_TYPE), type); } } /** * Visitor for {@link NoObjectType#getGreatestSubtype(JSType)}. */ private final Visitor<JSType> greatestSubtypeVisitor = new GreatestSupertypeVisitor(); private class GreatestSupertypeVisitor implements Visitor<JSType>, Serializable { private static final long serialVersionUID = 1L; public JSType caseNoObjectType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseUnknownType() { return getNativeType(JSTypeNative.UNKNOWN_TYPE); } public JSType caseNoType() { return getNativeType(JSTypeNative.NO_TYPE); } public JSType caseBooleanType() { return getNativeType(JSTypeNative.NO_TYPE); } public JSType caseFunctionType(FunctionType type) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseNullType() { return getNativeType(JSTypeNative.NO_TYPE); } public JSType caseNumberType() { return getNativeType(JSTypeNative.NO_TYPE); } public JSType caseObjectType(ObjectType type) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseStringType() { return getNativeType(JSTypeNative.NO_TYPE); } public JSType caseUnionType(UnionType that) { JSType anyObjectType = getNativeType(JSTypeNative.NO_OBJECT_TYPE); if (anyObjectType.isSubtype(that)) { return anyObjectType; } else if (that.isSubtype(anyObjectType)) { return that;

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> } else { return getNativeType(JSTypeNative.NO_TYPE); } } public JSType caseAllType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseVoidType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseEnumElementType(EnumElementType type) { return type.getPrimitiveType().visit(this); } } NoObjectType(JSTypeRegistry registry) { super(registry, null, null, null, null, null, null, true, true); } @Override public JSType getReturnType() { return this; } @Override public ObjectType getInstanceType() { return this; } @Override public TernaryValue testForEquality(JSType that) { return that.isEmptyType() ? TernaryValue.TRUE : TernaryValue.UNKNOWN; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return that.isObject() && !that.isNoType(); } } @Override public boolean isFunctionType() { return false; } @Override public boolean isNoObjectType() { return true; } @Override public JSType getLeastSupertype(JSType that) { return that.visit(leastSupertypeVisitor); } @Override public JSType getGreatestSubtype(JSType that) { return that.visit(greatestSubtypeVisitor); } @Override public ObjectType getImplicitPrototype() { return null; } @Override public String getReferenceName() { return null; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean equals(Object that) { return this == that; } @Override public int hashCode() { return System.identityHashCode(this); } @Override public int getPropertiesCount() { // Should never be called, returning the biggest number to highlight the // '

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>ReporterParser parser = new ErrorReporterParser(); private class ErrorReporterParser { void addWarning(String messageId, String messageArg, int lineno, int charno) { errorReporter.warning(ScriptRuntime.getMessage1(messageId, messageArg), sourceName, lineno, null, charno); } void addWarning(String messageId, int lineno, int charno) { errorReporter.warning(ScriptRuntime.getMessage0(messageId), sourceName, lineno, null, charno); } } // The DocInfo with the fileoverview tag for the whole file. private JSDocInfo fileOverviewJSDocInfo = null; private State state; private final Map<String, Annotation> annotationNames; private Node.FileLevelJsDocBuilder fileLevelJsDocBuilder; /** * Sets the JsDocBuilder for the file-level (root) node of this parse. The * parser uses the builder to append any preserve annotations it encounters * in jsdoc comments. * * @param fileLevelJsDocBuilder */ void setFileLevelJsDocBuilder( Node.FileLevelJsDocBuilder fileLevelJsDocBuilder) { this.fileLevelJsDocBuilder = fileLevelJsDocBuilder; } /** * Sets the file overview JSDocInfo, in order to warn about multiple uses of * the @fileoverview tag in a file. */ void setFileOverviewJSDocInfo(JSDocInfo fileOverviewJSDocInfo) { this.fileOverviewJSDocInfo = fileOverviewJSDocInfo; } private enum State { SEARCHING_ANNOTATION, SEARCHING_NEWLINE, NEXT_IS_ANNOTATION } JsDocInfoParser(JsDocTokenStream stream, String sourceName, Config config, ErrorReporter errorReporter) { this.stream = stream; this.sourceName = sourceName; this.typeRegistry = config.registry; this.jsdocBuilder = new JSDocInfoBuilder(config.parseJsDocDocumentation); this.annotationNames = config.annotationNames; this.errorReporter = errorReporter; } /** * Parses a string containing a JsDoc type declaration, returning the * type if the parsing succeeded or {@code null} if it failed.

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Call(Node callNode) { return null; } @Override public boolean isSuperClassReference(String propertyName) { return false; } @Override public String extractClassNameIfProvide(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String extractClassNameIfRequire(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String getExportPropertyFunction() { return null; } @Override public String getExportSymbolFunction() { return null; } @Override public List<String> identifyTypeDeclarationCall(Node n) { return null; } @Override public String identifyTypeDefAssign(Node n) { return null; } @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { // do nothing } @Override public String getAbstractMethodName() { return null; } @Override public String getSingletonGetterClassName(Node callNode) { return null; } @Override public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { // do nothing. } @Override public DelegateRelationship getDelegateRelationship(Node callNode) { return null; } @Override public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate) { // do nothing. } @Override public String getDelegateSuperclassName() { return null; } @Override public void defineDelegateProxyProperties( JSTypeRegistry registry, Scope scope, Map<ObjectType, ObjectType> delegateProxyMap) { // do nothing. } @Override public String getGlobalObject() { return "window"; } @Override public boolean isPropertyTestFunction(Node call) { return false; } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { return null; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> abstract T processSwitchCase(SwitchCase caseNode); abstract T processSwitchStatement(SwitchStatement statementNode); abstract T processThrowStatement(ThrowStatement statementNode); abstract T processTryStatement(TryStatement statementNode); abstract T processUnaryExpression(UnaryExpression exprNode); abstract T processVariableDeclaration(VariableDeclaration declarationNode); abstract T processVariableInitializer(VariableInitializer initializerNode); abstract T processWhileLoop(WhileLoop loopNode); abstract T processWithStatement(WithStatement statementNode); abstract T processIllegalToken(AstNode node); public T process(AstNode node) { switch (node.getType()) { case Token.ADD: case Token.AND: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GT: case Token.IN: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.OR: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.URSH: return processInfixExpression((InfixExpression) node); case Token.ARRAYLIT: return processArrayLiteral((ArrayLiteral) node); case Token.ASSIGN: case Token.ASSIGN_ADD: case Token.ASSIGN_BITAND: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_DIV: case Token.ASSIGN_LSH: case Token.ASSIGN_MOD: case Token.ASSIGN_MUL: case Token.ASSIGN_RSH: case Token.ASSIGN_SUB: case Token.ASSIGN_URSH: return processAssignment((Assignment) node); case Token.BITNOT: case Token.DEC: case Token.DELPROP: case Token.INC: case Token.NEG: case Token.NOT: case Token.POS: case Token.TYPEOF: case Token.VOID: return processUnaryExpression((UnaryExpression) node); case Token.BLOCK: if (node instanceof Block

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>SimpleOperatorType(int type) { switch (type) { case Token.ADD: case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.COMMA: case Token.DIV: case Token.EQ: case Token.GE: case Token.GETELEM: case Token.GETPROP: case Token.GT: case Token.INSTANCEOF: case Token.LE: case Token.LSH: case Token.LT: case Token.MOD: case Token.MUL: case Token.NE: case Token.NOT: case Token.RSH: case Token.SHEQ: case Token.SHNE: case Token.SUB: case Token.TYPEOF: case Token.VOID: case Token.POS: case Token.NEG: case Token.URSH: return true; default: return false; } } /** * Creates an EXPR_RESULT. * * @param child The expression itself. * @return Newly created EXPR node with the child as subexpression. */ public static Node newExpr(Node child) { return new Node(Token.EXPR_RESULT, child); } /** * Returns true if the node may create new mutable state, or change existing * state. * * @see <a href="http://www.xkcd.org/326/">XKCD Cartoon</a> */ static boolean mayEffectMutableState(Node n) { return checkForStateChangeHelper(n, true); } /** * Returns true if the node which may have side effects when executed. */ static boolean mayHaveSideEffects(Node n) { return checkForStateChangeHelper(n, false); } /** * Returns true if some node in n's subtree changes application state. * If {@code checkForNewObjects} is true, we assume that newly created * mutable objects (like object literals) change state. Otherwise, we assume * that they have no side effects. */ private static boolean checkForStateChangeHelper( Node n, boolean checkForNewObjects) { // Rather than id which ops may have side effects, id the ones // that we

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>BITAND: return 7; case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: return 8; case Token.LT: case Token.GT: case Token.LE: case Token.GE: case Token.INSTANCEOF: case Token.IN: return 9; case Token.LSH: case Token.RSH: case Token.URSH: return 10; case Token.SUB: case Token.ADD: return 11; case Token.MUL: case Token.MOD: case Token.DIV: return 12; case Token.INC: case Token.DEC: case Token.NEW: case Token.DELPROP: case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: return 13; case Token.ARRAYLIT: case Token.CALL: case Token.EMPTY: case Token.FALSE: case Token.FUNCTION: case Token.GETELEM: case Token.GETPROP: case Token.GET_REF: case Token.IF: case Token.LP: case Token.NAME: case Token.NULL: case Token.NUMBER: case Token.OBJECTLIT: case Token.REGEXP: case Token.RETURN: case Token.STRING: case Token.THIS: case Token.TRUE: return 15; default: throw new Error("Unknown precedence for " + Node.tokenToName(type) + " (type " + type + ")"); } } /** * Returns true if the operator is associative. * e.g. (a * b) * c = a * (b * c) * Note: "+" is not associative because it is also the concatentation * for strings. e.g. "a" + (1 + 2) is not "a" + 1 + 2 */ static boolean isAssociative(int type) { switch (type) { case Token.MUL: case Token.AND: case Token.OR: case Token.BITOR: case Token

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> case Token.MOD: return "%"; case Token.BITNOT: return "~"; case Token.ADD: return "+"; case Token.SUB: return "-"; case Token.POS: return "+"; case Token.NEG: return "-"; case Token.ASSIGN: return "="; case Token.ASSIGN_BITOR: return "|="; case Token.ASSIGN_BITXOR: return "^="; case Token.ASSIGN_BITAND: return "&="; case Token.ASSIGN_LSH: return "<<="; case Token.ASSIGN_RSH: return ">>="; case Token.ASSIGN_URSH: return ">>>="; case Token.ASSIGN_ADD: return "+="; case Token.ASSIGN_SUB: return "-="; case Token.ASSIGN_MUL: return "*="; case Token.ASSIGN_DIV: return "/="; case Token.ASSIGN_MOD: return "%="; case Token.VOID: return "void"; case Token.TYPEOF: return "typeof"; case Token.INSTANCEOF: return "instanceof"; default: return null; } } /** * Converts an operator's token value (see {@link Token}) to a string * representation or fails. * * @param operator the operator's token value to convert * @return the string representation * @throws Error if the token value is not an operator */ static String opToStrNoFail(int operator) { String res = opToStr(operator); if (res == null) { throw new Error("Unknown op " + operator + ": " + Token.name(operator)); } return res; } /** * @return true if n or any of its children are of the specified type. * Does not traverse into functions. */ static boolean containsTypeInOuterScope(Node node, int type) { return containsType(node, type, Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); } /** * @return true if n or any of its children are of the specified type */ static boolean containsType(Node node, int type, Predicate<Node> traverseChildrenPred) { return has(node, new MatchNodeType(type), traverseChildrenPred); } /**

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>ertype of a record type * of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to * A and matches all constraints. Similarly, a defined type can be assigned * to a record type so long as that defined type matches all property * constraints of the record type. A record type of the form { a : A, b : B } * can be assigned to a record of type { a : A }. * * */ public class RecordType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private Map<String, JSType> properties = new HashMap<String, JSType>(); private boolean isFrozen = false; /** * Creates a record type. * * @param registry The type registry under which this type lives. * @param properties A map of all the properties of this record type. */ RecordType(JSTypeRegistry registry, Map<String, JSType> properties) { super(registry, null, null); for (String property : properties.keySet()) { defineDeclaredProperty(property, properties.get(property), false); } // Freeze the record type. isFrozen = true; } @Override public boolean equals(Object other) { if (!(other instanceof RecordType)) { return false; } // Compare properties. RecordType otherRecord = (RecordType) other; return otherRecord.properties.equals(properties); } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { if (isFrozen) { return false; } if (!inferred) { properties.put(propertyName, type); } return super.defineProperty(propertyName, type, inferred, inExterns); } @Override public JSType getLeastSupertype(JSType that) { if (!that.isRecordType()) { return super.getLeastSupertype(that); } RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The least supertype consist of those properties of the record

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> // type that both record types hold in common both by name and // type of the properties themselves. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && thatRecord.getPropertyType(property).equals( getPropertyType(property))) { builder.addProperty(property, getPropertyType(property)); } } return builder.build(); } @Override public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).equals( getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property)); } for (String property : thatRecord.properties.keySet()) { if (!hasProperty(property)) { builder.addProperty(property, thatRecord.getPropertyType(property)); } } return builder.build(); } JSType greatestSubtype = super.getGreatestSubtype(that); if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) { // In this branch, the other type is some object type. We find // the greatest subtype with the following algorithm: // 1) For each property "x" of this record type, take the union // of all classes with a property "x" with a compatible property type. // and which are a subtype of {@code that}. // 2) Take the intersection of all of these unions. for (Map.Entry<String, JSType> entry : properties.entrySet()) { String propName = entry.getKey(); JSType propType = entry.getValue(); UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (ObjectType alt : registry.getTypesWithProperty(propName)) { JSType altPropType = alt.getPropertyType(propName); if (

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>altPropType != null && !alt.equals(this) && alt.isSubtype(that) && (propType.isUnknownType() || altPropType.isUnknownType() || altPropType.equals(propType))) { builder.addAlternate(alt); } } greatestSubtype = greatestSubtype.getLeastSupertype(builder.build()); } } return greatestSubtype; } @Override public boolean isRecordType() { return true; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } // Top of the record types is the empty record, or OBJECT_TYPE. if (registry.getNativeObjectType( JSTypeNative.OBJECT_TYPE).isSubtype(that)) { return true; } // A type is a subtype of a record type if it itself is a record // type and it has at least the same members as the parent record type // with the same types. if (!that.isRecordType()) { return false; } return RecordType.isSubtype(this, (RecordType) that); } /** Determines if typeA is a subtype of typeB */ static boolean isSubtype(ObjectType typeA, RecordType typeB) { // typeA is a subtype of record type typeB iff: // 1) typeA has all the properties declared in typeB. // 2) And for each property of typeB, // 2a) if the property of typeA is declared, it must be equal // to the type of the property of typeB, // 2b) otherwise, it must be a subtype of the property of typeB. // // To figure out why this is true, consider the following pseudo-code: // /** @type {{a: (Object,null)}} */ var x; // /** @type {{a: !Object}} */ var y; // var z = {a: {}}; // x.a = null; // // y cannot be assigned to x, because line 4 would violate y's declared // properties. But z can be assigned to x. Even though z and y are the // same type, the properties of z are inferred--

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.JSTypeNative.ALL_TYPE; /** * This type is for built-in error constructors. * * */ class ErrorFunctionType extends FunctionType { private static final long serialVersionUID = 1L; ErrorFunctionType(JSTypeRegistry registry, String name) { super(registry, name, null, registry.createOptionalParameters(

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> registry.getNativeType(ALL_TYPE), registry.getNativeType(ALL_TYPE), registry.getNativeType(ALL_TYPE)), null, null, null, true, true); } @Override public JSType getReturnType() { return getInstanceType(); } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; import com.google.javascript.rhino.ErrorReporter; /** * All type, representing all values. * * */ public final class AllType extends JSType { private static final long serialVersionUID = 1L; AllType(JSTypeRegistry registry) { super(registry); }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> /** * The All type is the greatest type (top) and is never a subtype of * another except itself or the Unknown type. * @return {@code this.equals(that)} */ @Override public boolean isSubtype(JSType that) { return that.isAllType() || that.isUnknownType(); } @Override public boolean isAllType() { return true; } @Override public boolean matchesStringContext() { // Be lenient. return true; } @Override public boolean matchesObjectContext() { // Be lenient. return true; } @Override public boolean canBeCalled() { return false; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public JSType getLeastSupertype(JSType that) { if (that.isUnknownType()) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return this; } @Override public JSType getGreatestSubtype(JSType that) { return that; } @Override public String toString() { return "*"; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseAllType(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { return this; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE; import java.io.Serializable; import java.util.Iterator; import java.util.List; import java.util.Set; /** * A builder for union types. * * */ class UnionTypeBuilder implements Serializable { private static final long serialVersionUID = 1L; // If the best we can do is say "this object is one of twenty things", // then we should just give up and admit that we have no clue. private static final int MAX_UNION_SIZE = 20; private final JSTypeRegistry registry; private final List<JSType> alternates = Lists.newArrayList(); private boolean isAllType = false; private boolean isNativeUnknownType = false; private boolean areAllUnknownsChecked = true; // Memoize the result, in case build() is called multiple times. private JSType result = null; UnionTypeBuilder(JSTypeRegistry registry) { this.registry = registry; } /** * Adds an alternate to the union type under construction. Returns this * for easy chaining. */ UnionTypeBuilder addAlternate(JSType alternate) { // build() returns the bottom type by default, so we can // just bail out early here. if (alternate.isNoType()) { return this; } isAllType = isAllType || alternate.isAllType(); boolean isAlternateUnknown = alternate instanceof UnknownType; isNativeUnknownType = isNativeUnknownType || isAlternateUnknown; if (isAlternateUnknown) { areAllUnknownsChecked = areAllUnknownsChecked && alternate.isCheckedUnknownType(); } if (!isAllType && !isNativeUnknownType) { if (alternate instanceof UnionType) { UnionType union = (UnionType) alternate; for (JSType unionAlt : union.getAlternates()) { addAlternate(unionAlt); } } else { if (!alternate.isUnknownType()) { Iterator<JSType> it = alternates.iterator(); while (it.hasNext()) { JSType current = it.next();

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> if (!current.isUnknownType()) { if (alternate.isSubtype(current)) { // Alternate is unnecessary. return this; } else if (current.isSubtype(alternate)) { // Alternate makes current obsolete it.remove(); } } } } alternates.add(alternate); result = null; // invalidate the memoized result } } else { result = null; } return this; } /** * Creates a union. * @return A UnionType if it has two or more alternates, the * only alternate if it has one and otherwise {@code NO_TYPE}. */ JSType build() { if (result == null) { if (isAllType) { result = registry.getNativeType(ALL_TYPE); } else if (isNativeUnknownType) { if (areAllUnknownsChecked) { result = registry.getNativeType(CHECKED_UNKNOWN_TYPE); } else { result = registry.getNativeType(UNKNOWN_TYPE); } } else { Set<JSType> alternateSet = Sets.newUnmodifiableHashSet(alternates); int size = alternateSet.size(); if (size > MAX_UNION_SIZE) { result = registry.getNativeType(UNKNOWN_TYPE); } else { if (size > 1) { result = new UnionType(registry, alternateSet); } else if (size == 1) { result = alternates.iterator().next(); } else { result = registry.getNativeType(NO_TYPE); } } } } return result; } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> defining the {@code LOCAL_CODES} enum * <pre>var LOCAL_CODES = {A: 3, B: 9, C: 8}</pre> * the primitive type of the the constants is {@code number}. */ private JSType primitiveType; // The primitive type, if it is an object. private ObjectType primitiveObjectType; private final String name; EnumElementType(JSTypeRegistry registry, JSType elementType, String name) { super(registry); this.primitiveType = elementType; this.primitiveObjectType = elementType.toObjectType(); this.name = name; } @Override public boolean isEnumElementType() { return true; } @Override public boolean matchesNumberContext() { return primitiveType.matchesNumberContext(); } @Override public boolean matchesStringContext() { return primitiveType.matchesStringContext(); } @Override public boolean matchesObjectContext() { return primitiveType.matchesObjectContext(); } @Override public boolean canBeCalled() { return primitiveType.canBeCalled(); } @Override public boolean isObject() { return primitiveType.isObject(); } @Override public TernaryValue testForEquality(JSType that) { return primitiveType.testForEquality(that); } /** * This predicate determines whether objects of this type can have the null * value, and therefore can appear in contexts where null is expected. * * @return true for everything but Number and Boolean types. */ @Override public boolean isNullable() { return primitiveType.isNullable(); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean equals(Object that) { if (this == that) { return true; } else if (that instanceof JSType && this.isNominalType()) { ObjectType thatObj = ObjectType.cast((JSType) that); if (thatObj != null && thatObj.isNominalType()) { return getReferenceName().equals(thatObj.getReferenceName()); } } return false; } /** * If this is equal to a NamedType object, its hashCode must be equal * to the hashCode of the NamedType object. */ @Override

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>AND: return "bitand"; case Token.EQ: return "eq"; case Token.NE: return "ne"; case Token.LT: return "lt"; case Token.LE: return "le"; case Token.GT: return "gt"; case Token.GE: return "ge"; case Token.LSH: return "lsh"; case Token.RSH: return "rsh"; case Token.URSH: return "ursh"; case Token.ADD: return "add"; case Token.SUB: return "sub"; case Token.MUL: return "mul"; case Token.DIV: return "div"; case Token.MOD: return "mod"; case Token.BITNOT: return "bitnot"; case Token.NEG: return "neg"; case Token.NEW: return "new"; case Token.DELPROP: return "delprop"; case Token.TYPEOF: return "typeof"; case Token.GETPROP: return "getprop"; case Token.SETPROP: return "setprop"; case Token.GETELEM: return "getelem"; case Token.SETELEM: return "setelem"; case Token.CALL: return "call"; case Token.NAME: return "name"; case Token.NUMBER: return "number"; case Token.STRING: return "string"; case Token.NULL: return "null"; case Token.THIS: return "this"; case Token.FALSE: return "false"; case Token.TRUE: return "true"; case Token.SHEQ: return "sheq"; case Token.SHNE: return "shne"; case Token.REGEXP: return "regexp"; case Token.POS: return "pos"; case Token.BINDNAME: return "bindname"; case Token.THROW: return "throw"; case Token.IN: return "in"; case Token.INSTANCEOF: return "instanceof"; case Token.GETVAR: return "getvar"; case Token.SETVAR: return "setvar"; case Token.TRY: return "try"; case Token.TYPEOF

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; import static com.google.javascript.rhino.jstype.TernaryValue.FALSE; import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN; /** * Number type. * */ public class NumberType extends ValueType { private static final long serialVersionUID = 1L; NumberType(JSTypeRegistry registry) { super(registry); } @

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> constructor; InstanceObjectType(JSTypeRegistry registry, FunctionType constructor) { this(registry, constructor, false); } InstanceObjectType(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getReferenceName() { return getConstructor().getReferenceName(); } @Override public boolean hasReferenceName() { return getConstructor().hasReferenceName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns); } @Override public String toString() { return constructor.getReferenceName(); } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getReferenceName()); } @Override public boolean isInstanceType() { return true; } @Override public boolean isArrayType() { return getConstructor().isNative() && "Array".equals(getReferenceName()); } @Override public boolean isStringObjectType() { return getConstructor().isNative() && "String".equals(getReferenceName()); } @Override public boolean isBooleanObjectType() { return getConstructor().isNative() && "Boolean".equals(getReferenceName()); } @Override public boolean isNumberObjectType() { return getConstructor().isNative() && "Number".equals(getReferenceName()); } @Override public boolean isDateType() { return getConstructor().isNative() && "Date".equals(getReferenceName()); } @Override public boolean isRegexpType() { return getConstructor().isNative() && "RegExp".equals(getReferenceName()); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean equals(Object that) { if

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>1L; NullType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isNullType() || that.isVoidType()) { return TRUE; } if (that.isUnknownType() || that.isNullable()) { return UNKNOWN; } return FALSE; } @Override public String toString() { return "null"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNullType(); } }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> ownerFunction; FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction, ObjectType implicitPrototype, boolean isNative) { super(registry, null /* has no class name */, implicitPrototype, isNative); this.ownerFunction = ownerFunction; } FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction, ObjectType implicitPrototype) { this(registry, ownerFunction, implicitPrototype, false); } @Override public String getReferenceName() { if (ownerFunction == null) { return "{...}.prototype"; } else { return ownerFunction.getReferenceName() + ".prototype"; } } @Override public boolean hasReferenceName() { return ownerFunction != null && ownerFunction.hasReferenceName(); } @Override public boolean isFunctionPrototypeType() { return true; } public FunctionType getOwnerFunction() { return ownerFunction; } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return getOwnerFunction().getImplementedInterfaces(); } // The owner will always be a resolved type, so there's no need to set // the ownerFunction in resolveInternal. // (it would lead to infinite loops if we did). // JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Type(JSTypeNative.NUMBER_STRING, NUMBER_STRING); // Native object properties are filled in by externs... // (String, string) JSType STRING_VALUE_OR_OBJECT_TYPE = createUnionType(STRING_OBJECT_TYPE, STRING_TYPE); registerNativeType( JSTypeNative.STRING_VALUE_OR_OBJECT_TYPE, STRING_VALUE_OR_OBJECT_TYPE); // (Number, number) JSType NUMBER_VALUE_OR_OBJECT_TYPE = createUnionType(NUMBER_OBJECT_TYPE, NUMBER_TYPE); registerNativeType( JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE); // unknown function type, i.e. (?...) -> ? FunctionType U2U_FUNCTION_TYPE = createFunctionType(UNKNOWN_TYPE, true, UNKNOWN_TYPE); registerNativeType(JSTypeNative.U2U_FUNCTION_TYPE, U2U_FUNCTION_TYPE); // unknown constructor type, i.e. (?...) -> ? with the NoObject type // as instance type FunctionType U2U_CONSTRUCTOR_TYPE = // This is equivalent to // createConstructorType(UNKNOWN_TYPE, true, UNKNOWN_TYPE), but, // in addition, overrides getInstanceType() to return the NoObject type // instead of a new anonymous object. new FunctionType(this, "Function", null, createParametersWithVarArgs( UNKNOWN_TYPE), UNKNOWN_TYPE, NO_OBJECT_TYPE, null, true, true) { private static final long serialVersionUID = 1L; @Override public FunctionType getConstructor() { return registry.getNativeFunctionType( JSTypeNative.FUNCTION_FUNCTION_TYPE); } }; // The U2U_CONSTRUCTOR is weird, because it's the supertype of its // own constructor. registerNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE, U2U_CONSTRUCTOR_TYPE); registerNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE, U2U_CONSTRUCTOR_TYPE); FUNCTION_FUNCTION_TYPE.setInstanceType(U2U_CONSTRUCTOR_TYPE); U2U_CONSTRUCTOR_TYPE.setImplicitPrototype(FUNCTION_PROTOTYPE); // least

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>.VOID_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined"); register(getNativeType(JSTypeNative.VOID_TYPE), "void"); register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function"); } private void register(JSType type) { register(type, type.toString()); } private void register(JSType type, String name) { namesToTypes.put(name, type); // Add all the namespaces in which this name lives. while (name.indexOf('.') > 0) { name = name.substring(0, name.lastIndexOf('.')); namespaces.add(name); } } private void registerNativeType(JSTypeNative typeId, JSType type) { nativeTypes[typeId.ordinal()] = type; } /** * Tells the type system that {@code owner} may have a property named * {@code propertyName}. This allows the registry to keep track of what * types a property is defined upon. * * This is NOT the same as saying that {@code owner} must have a property * named type. ObjectType#hasProperty attempts to minimize false positives * ("if we're not sure, then don't type check this property"). The type * registry, on the other hand, should attempt to minimize false negatives * ("if this property is assigned anywhere in the program, it must * show up in the type registry"). */ public void registerPropertyOnType(String propertyName, ObjectType owner) { Set<ObjectType> typeSet = typesIndexedByProperty.get(propertyName); if (typeSet == null) { typesIndexedByProperty.put(propertyName, typeSet = Sets.newHashSet()); } greatestSubtypeByProperty.remove(propertyName); typeSet.add(owner); } /** * Gets the greatest subtype of the {@code type} that has a property * {@code propertyName} defined on it. */ public JSType getGreatestSubtypeWithProperty( JSType type, String propertyName) { if (greatestSubtypeByProperty.containsKey(propertyName)) { return greatestSubtypeByProperty.get(propertyName) .getGreatestSubtype(type); } if (typesIndexedByProperty.containsKey(propertyName)) {

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>io.Serializable; import java.util.Comparator; import java.util.List; /** * Represents JavaScript value types.<p> * * Types are split into two separate families: value types and object types. * * A special {@link UnknownType} exists to represent a wildcard type on which * no information can be gathered. In particular, it can assign to everyone, * is a subtype of everyone (and everyone is a subtype of it).<p> * * If you remove the {@link UnknownType}, the set of types in the type system * forms a lattice with the {@link #isSubtype} relation defining the partial * order of types. All types are united at the top of the lattice by the * {@link AllType} and at the bottom by the {@link NoType}.<p> * * * */ public abstract class JSType implements Serializable { private static final long serialVersionUID = 1L; private boolean resolved = false; private JSType resolveResult = null; public static final String UNKNOWN_NAME = "Unknown class name"; public static final String NOT_A_CLASS = "Not declared as a constructor"; public static final String NOT_A_TYPE = "Not declared as a type name"; public static final String EMPTY_TYPE_COMPONENT = "Named type with empty name component"; /** * Total ordering on types based on their textual representation. * This is used to have a deterministic output of the toString * method of the union type since this output is used in tests. */ static final Comparator<JSType> ALPHA = new Comparator<JSType>() { public int compare(JSType t1, JSType t2) { return t1.toString().compareTo(t2.toString()); } }; // A flag set on enum definition tree nodes public static final int ENUMDECL = 1; public static final int NOT_ENUMDECL = 0; final JSTypeRegistry registry; JSType(JSTypeRegistry registry) { this.registry = registry; } /** * Utility method for less verbose code. */ JSType getNativeType(JSTypeNative typeId) { return registry.getNativeType(typeId); } /** * Gets the docInfo

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>TestForShallowEqualityWith(JSType that) { return this.isSubtype(that) || that.isSubtype(this); } /** * Tests whether this type is nullable. */ public boolean isNullable() { return this.isSubtype(getNativeType(JSTypeNative.NULL_TYPE)); } /** * Gets the least supertype of {@code this} and {@code that}. * The least supertype is the join (&#8744;) or supremum of both types in the * type lattice.<p> * Examples: * <ul> * <li>{@code number &#8744; *} = {@code *}</li> * <li>{@code number &#8744; Object} = {@code (number, Object)}</li> * <li>{@code Number &#8744; Object} = {@code Object}</li> * </ul> * @return {@code this &#8744; that} */ public JSType getLeastSupertype(JSType that) { if (that.isUnionType()) { // Union types have their own implementation of getLeastSupertype. return that.getLeastSupertype(this); } return getLeastSupertype(this, that); } /** * A generic implementation meant to be used as a helper for common * getLeastSupertype implementations. */ static JSType getLeastSupertype(JSType thisType, JSType thatType) { if (thatType.isEmptyType() || thatType.isAllType()) { // Defer to the implementations of the end lattice elements when // possible. return thatType.getLeastSupertype(thisType); } return thisType.registry.createUnionType(thisType, thatType); } /** * Gets the greatest subtype of {@code this} and {@code that}. * The greatest subtype is the meet (&#8743;) or infimum of both types in the * type lattice.<p> * Examples * <ul> * <li>{@code Number &#8743; Any} = {@code Any}</li> * <li>{@code number &#8743; Object} = {@code Any}</li> * <li>{@code Number

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> (thatType.isUnknownType()) { return true; } // equality if (thisType.equals(thatType)) { return true; } // all type if (thatType.isAllType()) { return true; } // unions if (thatType instanceof UnionType) { UnionType union = (UnionType)thatType; for (JSType element : union.alternates) { if (thisType.isSubtype(element)) { return true; } } } // named types if (thatType instanceof NamedType) { return thisType.isSubtype(((NamedType)thatType).referencedType); } return false; } /** * Visit this type with the given visitor. * @see com.google.javascript.rhino.jstype.Visitor * @return the value returned by the visitor */ public abstract <T> T visit(Visitor<T> visitor); /** * Resolve this type in the given scope. * * The returned value must be equal to {@code this}, as defined by * {@link Object#equals}. It may or may not be the same object. This method * may modify the internal state of {@code this}, as long as it does * so in a way that preserves Object equality. * * For efficiency, we should only resolve a type once per compilation job. * For incremental compilations, one compilation job may need the * artifacts from a previous generation, so we will eventually need * a generational flag instead of a boolean one. */ public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) { if (resolved) { // TODO(nicksantos): Check to see if resolve() looped back on itself. // Preconditions.checkNotNull(resolveResult); if (resolveResult == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return resolveResult; } resolved = true; resolveResult = resolveInternal(t, scope); return resolveResult; } /** * @see #resolve */ abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); void setResolvedTypeInternal(JSType type) { resolveResult = type

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> * */ final class ArrowType extends JSType { private static final long serialVersionUID = 1L; final Node parameters; JSType returnType; ArrowType(JSTypeRegistry registry, Node parameters, JSType returnType) { super(registry); this.parameters = parameters; this.returnType = returnType; } @Override public boolean isSubtype(JSType other) { if (!(other instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) other; // this.returnType <: that.returnType (covariant) // If the return type is null, this is equivalent to unknown so we do not // base our decision on that. if (this.returnType != null && that.returnType != null && !this.returnType.isSubtype(that.returnType)) { return false; } // that.paramType[i] <: this.paramType[i] (contravariant) // TODO(nicksantos): This is incorrect. It should be invariant. // Follow up with closure team on how to fix this without everyone // hating on us. // // If the parameter list is null, this is equivalent of ?... so we do not // base our decision on that. if (this.parameters != null && that.parameters != null) { Node thisParam = parameters.getFirstChild(); Node thatParam = that.parameters.getFirstChild(); while (thisParam != null && thatParam != null) { JSType thisParamType = thisParam.getJSType(); if (thisParamType != null) { JSType thatParamType = thatParam.getJSType(); if (thatParamType == null || !thatParamType.isSubtype(thisParamType)) { return false; } } boolean thisIsVarArgs = thisParam.isVarArgs(); boolean thatIsVarArgs = thatParam.isVarArgs(); // don't advance if we have variable arguments if (!thisIsVarArgs) { thisParam = thisParam.getNext(); } if (!thatIsVarArgs) { thatParam = thatParam.getNext(); } // both var_args indicates the end if (thisIsVarArgs && thatIsVarArgs) { thisParam = null; that

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>.JSTypeRegistry; import com.google.javascript.rhino.jstype.ObjectType; import com.google.javascript.rhino.jstype.RecordTypeBuilder; import junit.framework.TestCase; public abstract class BaseJSTypeTestCase extends TestCase { protected JSTypeRegistry registry; protected TestErrorReporter errorReporter; protected JSType ALL_TYPE; protected ObjectType NO_OBJECT_TYPE; protected ObjectType NO_TYPE; protected JSType ARRAY_FUNCTION_TYPE; protected ObjectType ARRAY_TYPE; protected JSType BOOLEAN_OBJECT_FUNCTION_TYPE; protected ObjectType BOOLEAN_OBJECT_TYPE; protected JSType BOOLEAN_TYPE; protected JSType CHECKED_UNKNOWN_TYPE; protected JSType DATE_FUNCTION_TYPE; protected ObjectType DATE_TYPE; protected JSType ERROR_FUNCTION_TYPE; protected ObjectType ERROR_TYPE; protected JSType EVAL_ERROR_FUNCTION_TYPE; protected ObjectType EVAL_ERROR_TYPE; protected FunctionType FUNCTION_FUNCTION_TYPE; protected FunctionType FUNCTION_INSTANCE_TYPE; protected ObjectType FUNCTION_PROTOTYPE; protected JSType GREATEST_FUNCTION_TYPE; protected JSType LEAST_FUNCTION_TYPE; protected JSType MATH_TYPE; protected JSType NULL_TYPE; protected JSType NUMBER_OBJECT_FUNCTION_TYPE; protected ObjectType NUMBER_OBJECT_TYPE; protected JSType NUMBER_STRING_BOOLEAN; protected JSType NUMBER_TYPE; protected FunctionType OBJECT_FUNCTION_TYPE; protected JSType OBJECT_NUMBER_STRING; protected JSType OBJECT_NUMBER_STRING_BOOLEAN; protected JSType OBJECT_PROTOTYPE; protected ObjectType OBJECT_TYPE; protected JSType RANGE_ERROR_FUNCTION_TYPE; protected ObjectType RANGE_ERROR_TYPE; protected JSType REFERENCE_ERROR_FUNCTION_TYPE; protected ObjectType REFERENCE_ERROR_TYPE; protected JSType REGEXP_FUNCTION_TYPE; protected ObjectType REGEXP_TYPE; protected JSType STRING_OBJECT_FUNCTION_TYPE; protected ObjectType STRING_OBJECT_TYPE; protected JSType STRING_TYPE; protected JSType SYNTAX_ERROR_FUNCTION_TYPE; protected ObjectType SYNTAX_ERROR_TYPE; protected JSType TYPE_ERROR_FUNCTION_TYPE; protected ObjectType TYPE_ERROR_TYPE; protected

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> FunctionType U2U_CONSTRUCTOR_TYPE; protected FunctionType U2U_FUNCTION_TYPE; protected ObjectType UNKNOWN_TYPE; protected JSType URI_ERROR_FUNCTION_TYPE; protected ObjectType URI_ERROR_TYPE; protected JSType VOID_TYPE; protected int NATIVE_PROPERTIES_COUNT; @Override protected void setUp() throws Exception { super.setUp(); errorReporter = new TestErrorReporter(null, null); registry = new JSTypeRegistry(errorReporter); initTypes(); } protected void initTypes() { ALL_TYPE = registry.getNativeType(JSTypeNative.ALL_TYPE); NO_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE); NO_TYPE = registry.getNativeObjectType(JSTypeNative.NO_TYPE); ARRAY_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE); ARRAY_TYPE = registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE); BOOLEAN_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE); BOOLEAN_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE); BOOLEAN_TYPE = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE); CHECKED_UNKNOWN_TYPE = registry.getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE); DATE_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.DATE_FUNCTION_TYPE); DATE_TYPE = registry.getNativeObjectType(JSTypeNative.DATE_TYPE); ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.ERROR_FUNCTION_TYPE); ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.ERROR_TYPE); EVAL_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.EVAL_ERROR_FUNCTION_TYPE); EVAL_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.EVAL_ERROR_TYPE); FUNCTION_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.FUNCTION_FUNCTION_TYPE); FUNCTION_INSTANCE_TYPE = registry.getNativeFunctionType(JS

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>TypeNative.FUNCTION_INSTANCE_TYPE); FUNCTION_PROTOTYPE = registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE); GREATEST_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.GREATEST_FUNCTION_TYPE); LEAST_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.LEAST_FUNCTION_TYPE); NULL_TYPE = registry.getNativeType(JSTypeNative.NULL_TYPE); NUMBER_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE); NUMBER_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE); NUMBER_STRING_BOOLEAN = registry.getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN); NUMBER_TYPE = registry.getNativeType(JSTypeNative.NUMBER_TYPE); OBJECT_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE); OBJECT_NUMBER_STRING = registry.getNativeType(JSTypeNative.OBJECT_NUMBER_STRING); OBJECT_NUMBER_STRING_BOOLEAN = registry.getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN); OBJECT_PROTOTYPE = registry.getNativeType(JSTypeNative.OBJECT_PROTOTYPE); OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); RANGE_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.RANGE_ERROR_FUNCTION_TYPE); RANGE_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.RANGE_ERROR_TYPE); REFERENCE_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.REFERENCE_ERROR_FUNCTION_TYPE); REFERENCE_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.REFERENCE_ERROR_TYPE); REGEXP_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.REGEXP_FUNCTION_TYPE); REGEXP_TYPE = registry.getNativeObjectType(JSTypeNative.REGEXP_TYPE); STRING_OBJECT_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE);

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> STRING_OBJECT_TYPE = registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE); STRING_TYPE = registry.getNativeType(JSTypeNative.STRING_TYPE); SYNTAX_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.SYNTAX_ERROR_FUNCTION_TYPE); SYNTAX_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.SYNTAX_ERROR_TYPE); TYPE_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.TYPE_ERROR_FUNCTION_TYPE); TYPE_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.TYPE_ERROR_TYPE); U2U_CONSTRUCTOR_TYPE = registry.getNativeFunctionType(JSTypeNative.U2U_CONSTRUCTOR_TYPE); U2U_FUNCTION_TYPE = registry.getNativeFunctionType(JSTypeNative.U2U_FUNCTION_TYPE); UNKNOWN_TYPE = registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); URI_ERROR_FUNCTION_TYPE = registry.getNativeType(JSTypeNative.URI_ERROR_FUNCTION_TYPE); URI_ERROR_TYPE = registry.getNativeObjectType(JSTypeNative.URI_ERROR_TYPE); VOID_TYPE = registry.getNativeType(JSTypeNative.VOID_TYPE); addNativeProperties(registry); NATIVE_PROPERTIES_COUNT = OBJECT_TYPE.getPropertiesCount(); } /** Adds a basic set of properties to the native types. */ public static void addNativeProperties(JSTypeRegistry registry) { JSType booleanType = registry.getNativeType(JSTypeNative.BOOLEAN_TYPE); JSType numberType = registry.getNativeType(JSTypeNative.NUMBER_TYPE); JSType stringType = registry.getNativeType(JSTypeNative.STRING_TYPE); JSType unknownType = registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); ObjectType objectType = registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); ObjectType arrayType = registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE); ObjectType dateType = registry.getNativeObjectType(JSTypeNative.DATE_TYPE); ObjectType regexpType = registry.getNativeObjectType(JSTypeNative.

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>REGEXP_TYPE); ObjectType booleanObjectType = registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE); ObjectType numberObjectType = registry.getNativeObjectType(JSTypeNative.NUMBER_OBJECT_TYPE); ObjectType stringObjectType = registry.getNativeObjectType(JSTypeNative.STRING_OBJECT_TYPE); ObjectType objectPrototype = registry .getNativeFunctionType(JSTypeNative.OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, objectPrototype, "constructor", objectType); addMethod(registry, objectPrototype, "toString", stringType); addMethod(registry, objectPrototype, "toLocaleString", stringType); addMethod(registry, objectPrototype, "valueOf", unknownType); addMethod(registry, objectPrototype, "hasOwnProperty", booleanType); addMethod(registry, objectPrototype, "isPrototypeOf", booleanType); addMethod(registry, objectPrototype, "propertyIsEnumerable", booleanType); ObjectType arrayPrototype = registry .getNativeFunctionType(JSTypeNative.ARRAY_FUNCTION_TYPE) .getPrototype(); addMethod(registry, arrayPrototype, "constructor", arrayType); addMethod(registry, arrayPrototype, "toString", stringType); addMethod(registry, arrayPrototype, "toLocaleString", stringType); addMethod(registry, arrayPrototype, "concat", arrayType); addMethod(registry, arrayPrototype, "join", stringType); addMethod(registry, arrayPrototype, "pop", unknownType); addMethod(registry, arrayPrototype, "push", numberType); addMethod(registry, arrayPrototype, "reverse", arrayType); addMethod(registry, arrayPrototype, "shift", unknownType); addMethod(registry, arrayPrototype, "slice", arrayType); addMethod(registry, arrayPrototype, "sort", arrayType); addMethod(registry, arrayPrototype, "splice", arrayType); addMethod(registry, arrayPrototype, "unshift", numberType); arrayType.defineDeclaredProperty("length", numberType, true); ObjectType booleanPrototype = registry .getNativeFunctionType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, booleanPrototype, "constructor", booleanObjectType); addMethod(registry, booleanPrototype, "toString", stringType); addMethod(registry

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>, booleanPrototype, "valueOf", booleanType); ObjectType datePrototype = registry .getNativeFunctionType(JSTypeNative.DATE_FUNCTION_TYPE) .getPrototype(); addMethod(registry, datePrototype, "constructor", dateType); addMethod(registry, datePrototype, "toString", stringType); addMethod(registry, datePrototype, "toDateString", stringType); addMethod(registry, datePrototype, "toTimeString", stringType); addMethod(registry, datePrototype, "toLocaleString", stringType); addMethod(registry, datePrototype, "toLocaleDateString", stringType); addMethod(registry, datePrototype, "toLocaleTimeString", stringType); addMethod(registry, datePrototype, "valueOf", numberType); addMethod(registry, datePrototype, "getTime", numberType); addMethod(registry, datePrototype, "getFullYear", numberType); addMethod(registry, datePrototype, "getUTCFullYear", numberType); addMethod(registry, datePrototype, "getMonth", numberType); addMethod(registry, datePrototype, "getUTCMonth", numberType); addMethod(registry, datePrototype, "getDate", numberType); addMethod(registry, datePrototype, "getUTCDate", numberType); addMethod(registry, datePrototype, "getDay", numberType); addMethod(registry, datePrototype, "getUTCDay", numberType); addMethod(registry, datePrototype, "getHours", numberType); addMethod(registry, datePrototype, "getUTCHours", numberType); addMethod(registry, datePrototype, "getMinutes", numberType); addMethod(registry, datePrototype, "getUTCMinutes", numberType); addMethod(registry, datePrototype, "getSeconds", numberType); addMethod(registry, datePrototype, "getUTCSeconds", numberType); addMethod(registry, datePrototype, "getMilliseconds", numberType); addMethod(registry, datePrototype, "getUTCMilliseconds", numberType); addMethod(registry, datePrototype, "getTimezoneOffset", numberType); addMethod(registry, datePrototype, "setTime", numberType); addMethod(registry, datePrototype, "setMilliseconds", numberType); addMethod(registry, datePrototype, "setUTCMilliseconds", number

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>Type); addMethod(registry, datePrototype, "setSeconds", numberType); addMethod(registry, datePrototype, "setUTCSeconds", numberType); addMethod(registry, datePrototype, "setMinutes", numberType); addMethod(registry, datePrototype, "setUTCMinutes", numberType); addMethod(registry, datePrototype, "setHours", numberType); addMethod(registry, datePrototype, "setUTCHours", numberType); addMethod(registry, datePrototype, "setDate", numberType); addMethod(registry, datePrototype, "setUTCDate", numberType); addMethod(registry, datePrototype, "setMonth", numberType); addMethod(registry, datePrototype, "setUTCMonth", numberType); addMethod(registry, datePrototype, "setFullYear", numberType); addMethod(registry, datePrototype, "setUTCFullYear", numberType); addMethod(registry, datePrototype, "toUTCString", stringType); addMethod(registry, datePrototype, "toGMTString", stringType); ObjectType numberPrototype = registry .getNativeFunctionType(JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, numberPrototype, "constructor", numberObjectType); addMethod(registry, numberPrototype, "toString", stringType); addMethod(registry, numberPrototype, "toLocaleString", stringType); addMethod(registry, numberPrototype, "valueOf", numberType); addMethod(registry, numberPrototype, "toFixed", stringType); addMethod(registry, numberPrototype, "toExponential", stringType); addMethod(registry, numberPrototype, "toPrecision", stringType); ObjectType regexpPrototype = registry .getNativeFunctionType(JSTypeNative.REGEXP_FUNCTION_TYPE) .getPrototype(); addMethod(registry, regexpPrototype, "constructor", regexpType); addMethod(registry, regexpPrototype, "exec", registry.createNullableType(arrayType)); addMethod(registry, regexpPrototype, "test", booleanType); addMethod(registry, regexpPrototype, "toString", stringType); regexpType.defineDeclaredProperty("source", stringType, true); regexpType.defineDeclaredProperty("global", booleanType, true); regexpType.defineDeclaredProperty("

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>ignoreCase", booleanType, true); regexpType.defineDeclaredProperty("multiline", booleanType, true); regexpType.defineDeclaredProperty("lastIndex", numberType, true); ObjectType stringPrototype = registry .getNativeFunctionType(JSTypeNative.STRING_OBJECT_FUNCTION_TYPE) .getPrototype(); addMethod(registry, stringPrototype, "constructor", stringObjectType); addMethod(registry, stringPrototype, "toString", stringType); addMethod(registry, stringPrototype, "valueOf", stringType); addMethod(registry, stringPrototype, "charAt", stringType); addMethod(registry, stringPrototype, "charCodeAt", numberType); addMethod(registry, stringPrototype, "concat", stringType); addMethod(registry, stringPrototype, "indexOf", numberType); addMethod(registry, stringPrototype, "lastIndexOf", numberType); addMethod(registry, stringPrototype, "localeCompare", numberType); addMethod(registry, stringPrototype, "match", registry.createNullableType(arrayType)); addMethod(registry, stringPrototype, "replace", stringType); addMethod(registry, stringPrototype, "search", numberType); addMethod(registry, stringPrototype, "slice", stringType); addMethod(registry, stringPrototype, "split", arrayType); addMethod(registry, stringPrototype, "substring", stringType); addMethod(registry, stringPrototype, "toLowerCase", stringType); addMethod(registry, stringPrototype, "toLocaleLowerCase", stringType); addMethod(registry, stringPrototype, "toUpperCase", stringType); addMethod(registry, stringPrototype, "toLocaleUpperCase", stringType); stringObjectType.defineDeclaredProperty("length", numberType, true); } private static void addMethod( JSTypeRegistry registry, ObjectType receivingType, String methodName, JSType returnType) { receivingType.defineDeclaredProperty(methodName, new FunctionType(registry, null, null, null, returnType), true); } protected JSType createUnionType(JSType... variants) { return registry.createUnionType(variants); } protected RecordTypeBuilder createRecordTypeBuilder() { return new RecordTypeBuilder(registry); } protected JSType createNullableType(JSType type) { return registry.createNullableType(type); }

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> protected JSType createOptionalType(JSType type) { return registry.createOptionalType(type); } /** * Asserts that a Node representing a type expression resolves to the * correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, Node actual) { assertTypeEquals(expected, new JSTypeExpression(actual, "", registry)); } /** * Asserts that a a type expression resolves to the correct {@code JSType}. */ protected void assertTypeEquals(JSType expected, JSTypeExpression actual) { assertEquals(expected, resolve(actual)); } /** * Resolves a type expression, expecting the given warnings. */ protected JSType resolve(JSTypeExpression n, String... warnings) { errorReporter.setWarnings(warnings); return n.evaluate(null); } /** * A definition of all extern types. This should be kept in sync with * javascript/externs/es3.js. This is used to check that the builtin types * declared in {@link JSTypeRegistry} have the same type as that in the * externs. It can also be used for any tests that want to use builtin types * in their externs. */ public static final String ALL_NATIVE_EXTERN_TYPES = "/**\n" + " * @constructor\n" + " * @param {*} opt_value\n" + " */\n" + "function Object(opt_value) {}\n" + "\n" + "/**\n" + " * @constructor\n" + " * @extends {Object}\n" + " * @param {*} var_args\n" + " */\n" + "\n" + "function Function(var_args) {}\n" + "/**\n" + " * @constructor\n" + " * @extends {Object}\n" + " * @param {*} var_args\n" + " * @return {!Array}\n" + " */\n" + "function Array(var_args) {}\n" + "\n" + "/**\n" + " * @constructor\n" + " * @param {*} opt_value\n"

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> * @param name the function's name or {@code null} to indicate that the * function is anonymous. * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. * @param parameters the function's parameters or {@code null} * to indicate that the parameter types are unknown. * @param returnType the function's return type or {@code null} to indicate * that the return type is unknown. */ @VisibleForTesting public FunctionType(JSTypeRegistry registry, String name, Node source, Node parameters, JSType returnType) { this(registry, name, source, parameters, returnType, null, null, false, false); } /** * Creates a function type. * @param registry the owner registry for this type * @param name the function's name or {@code null} to indicate that the * function is anonymous. * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. * @param parameters the function's parameters or {@code null} * to indicate that the parameter types are unknown. * @param returnType the function's return type or {@code null} to indicate * that the return type is unknown. * @param typeOfThis The type of {@code this} in non-constructors. May be * {@code null} to indicate that the type of {@code this} is unknown. */ public FunctionType(JSTypeRegistry registry, String name, Node source, Node parameters, JSType returnType, ObjectType typeOfThis) { this(registry, name, source, parameters, returnType, typeOfThis, null, false, false); } /** * Creates a function type. * @param registry the owner registry for this type * @param name the function's name or {@code null} to indicate that the * function is anonymous. * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. * @param parameters the function's parameters or {@code null} * to indicate that the parameter types are unknown. * @param returnType the function's return type or {@code

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> null} to indicate * that the return type is unknown. * @param typeOfThis The type of {@code this} in non-constructors. May be * {@code null} to indicate that the type of {@code this} is unknown. * @param templateTypeName The template type name or {@code null}. */ public FunctionType(JSTypeRegistry registry, String name, Node source, Node parameters, JSType returnType, ObjectType typeOfThis, String templateTypeName) { this(registry, name, source, parameters, returnType, typeOfThis, templateTypeName, false, false); } /** Creates an instance for a function that might be a constructor. */ FunctionType(JSTypeRegistry registry, String name, Node source, Node parameters, JSType returnType, ObjectType typeOfThis, String templateTypeName, boolean isConstructor, boolean nativeType) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE), nativeType); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); this.source = source; this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY; if (isConstructor) { this.typeOfThis = typeOfThis != null && typeOfThis.isNoObjectType() ? typeOfThis : new InstanceObjectType(registry, this, nativeType); } else { this.typeOfThis = typeOfThis != null ? typeOfThis : registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); } // The call type should be set up last because we are calling getReturnType, // which may be overloaded and depend on other properties being set. this.call = new ArrowType(registry, parameters, (returnType == null ? getReturnType() : returnType)); this.templateTypeName = templateTypeName; } /** Creates an instance for a function that is an interface. */ FunctionType(JSTypeRegistry registry, String name, Node source) { super(registry, name, registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE)); Preconditions.checkArgument(source == null || Token.FUNCTION == source.getType()); Preconditions.checkArgument(name != null); this.source = source; this.call = null; this

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return equals(registry.getNativeType(U2U_CONSTRUCTOR_TYPE)); } @Override public boolean isConstructor() { return kind == Kind.CONSTRUCTOR; } @Override public boolean isInterface() { return kind == Kind.INTERFACE; } @Override public boolean isOrdinaryFunction() { return kind == Kind.ORDINARY; } @Override public boolean isFunctionType() { return true; } @Override public boolean canBeCalled() { return true; } public Iterable<Node> getParameters() { Node n = getParametersNode(); if (n != null) { return n.children(); } else { return Collections.emptySet(); } } /** Gets an LP node that contains all params. May be null. */ public Node getParametersNode() { return call == null ? null : call.parameters; } /** Gets the minimum number of arguments that this function requires. */ public int getMinArguments() { // NOTE(nicksantos): There are some native functions that have optional // parameters before required parameters. This algorithm finds the position // of the last required parameter. int i = 0; int min = 0; for (Node n : getParameters()) { i++; if (!n.isOptionalArg() && !n.isVarArgs()) { min = i; } } return min; } /** * Gets the maximum number of arguments that this function requires, * or Integer.MAX_VALUE if this is a variable argument function. */ public int getMaxArguments() { Node params = getParametersNode(); if (params != null) { Node lastParam = params.getLastChild(); if (lastParam == null || !lastParam.isVarArgs()) { return params.getChildCount(); } } return Integer.MAX_VALUE; } public JSType getReturnType() { return call == null ? null : call.returnType; } /** * Gets the {@code prototype}

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> property of this function type. This is * equivalent to {@code (ObjectType) getPropertyType("prototype")}. */ public FunctionPrototypeType getPrototype() { // lazy initialization of the prototype field if (prototype == null) { setPrototype(new FunctionPrototypeType(registry, this, null)); } return prototype; } /** * Sets the prototype, creating the prototype object from the given * base type. * @param baseType The base type. */ public void setPrototypeBasedOn(ObjectType baseType) { if (prototype == null) { setPrototype( new FunctionPrototypeType( registry, this, baseType, isNativeObjectType())); } else { prototype.setImplicitPrototype(baseType); } } /** * Sets the prototype. * @param prototype the prototype. If this value is {@code null} it will * silently be discarded. */ public boolean setPrototype(FunctionPrototypeType prototype) { if (prototype == null) { return false; } // getInstanceType fails if the function is not a constructor if (isConstructor() && prototype == getInstanceType()) { return false; } this.prototype = prototype; if (isConstructor() || isInterface()) { FunctionType superClass = getSuperClassConstructor(); if (superClass != null) { superClass.addSubType(this); } } return true; } /** * Returns all interfaces implemented by a class or its superclass and any * superclasses for any of those interfaces. If this is called before all * types are resolved, it may return an incomplete set. */ public Iterable<ObjectType> getAllImplementedInterfaces() { Set<ObjectType> interfaces = Sets.newHashSet(); for (ObjectType type : getImplementedInterfaces()) { addRelatedInterfaces(type, interfaces); } return interfaces; } private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!constructor.isInterface()) { return; } set.add(instance); if (constructor.getSuperClassConstructor() != null) { addRelatedInterfaces( constructor.getSuperClassConstructor().getInstanceType(), set); } } } /** Returns interfaces

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> implemented directly by a class or its superclass. */ public Iterable<ObjectType> getImplementedInterfaces() { FunctionType superCtor = isConstructor() ? getSuperClassConstructor() : null; if (superCtor == null) { return implementedInterfaces; } else { return Iterables.concat( implementedInterfaces, superCtor.getImplementedInterfaces()); } } public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) { // Records this type for each implemented interface. for (ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } @Override public boolean hasProperty(String name) { return super.hasProperty(name) || "prototype".equals(name); } @Override public boolean hasOwnProperty(String name) { return super.hasOwnProperty(name) || "prototype".equals(name); } @Override public JSType getPropertyType(String name) { if ("prototype".equals(name)) { return getPrototype(); } else { if (!hasOwnProperty(name)) { if ("call".equals(name)) { // Define the "call" function lazily. Node params = getParametersNode(); if (params == null) { // If there's no params array, don't do any type-checking // in this CALL function. defineDeclaredProperty(name, new FunctionType(registry, null, null, null, getReturnType()), false); } else { params = params.cloneTree(); Node thisTypeNode = Node.newString(Token.NAME, "thisType"); thisTypeNode.setJSType( registry.createOptionalNullableType(getTypeOfThis())); params.addChildToFront(thisTypeNode); thisTypeNode.setOptionalArg(true); defineDeclaredProperty(name, new FunctionType(registry, null, null, params, getReturnType()), false); } } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // Ecma-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionType(registry, null, null, builder.build(), getReturnType()), false); } } return super.getPropertyType(name); } } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { if ("prototype".equals(name)) { ObjectType objType = type.toObjectType(); if (objType != null) { if (objType.equals(prototype)) { return true; } return setPrototype( new FunctionPrototypeType( registry, this, objType, isNativeObjectType())); } else { return false; } } return super.defineProperty(name, type, inferred, inExterns); } @Override public boolean isPropertyTypeInferred(String property) { return "prototype".equals(property) || super.isPropertyTypeInferred(property); } @Override public JSType getLeastSupertype(JSType that) { // NOTE(nicksantos): When we remove the unknown type, the function types // form a lattice with the universal constructor at the top of the lattice, // and the NoObject type at the bottom of the lattice. // // When we introduce the unknown type, it's much more difficult to make // heads or tails of the partial ordering of types, because there's no // clear hierarchy between the different components (parameter types and // return types) in the ArrowType. // // Rather than make the situation more complicated by introducing new // types (like unions of functions), we just fallback on the simpler // approach of using the universal constructor and the AnyObject as // the supremum and infinum of all function types. if (isFunctionType() && that.isFunctionType()) { if (equals(that)) { return this; } JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>); if (functionInstance.equals(that)) { return that; } else if (functionInstance.equals(this)) { return this; } return registry.getNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE); } return super.getLeastSupertype(that); } @Override public JSType getGreatestSubtype(JSType that) { if (isFunctionType() && that.isFunctionType()) { if (equals(that)) { return this; } JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE); if (functionInstance.equals(that)) { return this; } else if (functionInstance.equals(this)) { return that; } return registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return super.getGreatestSubtype(that); } /** * Given a constructor or an interface type, get its superclass constructor * or {@code null} if none exists. */ public FunctionType getSuperClassConstructor() { Preconditions.checkArgument(isConstructor() || isInterface()); ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return null; } return maybeSuperInstanceType.getConstructor(); } /** * Given a constructor or an interface type, find out whether the unknown * type is a supertype of the current type. */ public boolean hasUnknownSupertype() { Preconditions.checkArgument(isConstructor() || isInterface()); Preconditions.checkArgument(!this.isUnknownType()); // Potential infinite loop if our type system messes up or someone defines // a bad type. Otherwise the loop should always end. FunctionType ctor = this; while (true) { ObjectType maybeSuperInstanceType = ctor.getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return false; } if (maybeSuperInstanceType.isUnknownType()) { return true; } ctor = maybeSuperInstanceType.getConstructor(); if (ctor == null) { return false; } Preconditions.checkState(ctor.isConstructor() || ctor.isInterface()); } } /**

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> * Given a constructor or an interface type and a property, finds the * top-most superclass that has the property defined (including this * constructor). */ public JSType getTopMostDefiningType(String propertyName) { Preconditions.checkState(isConstructor() || isInterface()); Preconditions.checkArgument(getPrototype().hasProperty(propertyName)); FunctionType ctor = this; JSType topInstanceType; do { topInstanceType = ctor.getInstanceType(); ctor = ctor.getSuperClassConstructor(); } while (ctor != null && ctor.getPrototype().hasProperty(propertyName)); return topInstanceType; } /** * Two function types are equal if their signatures match. Since they don't * have signatures, two interfaces are equal if their names match. */ @Override public boolean equals(Object otherType) { if (!(otherType instanceof FunctionType)) { return false; } FunctionType that = (FunctionType) otherType; if (!that.isFunctionType()) { return false; } if (this.isConstructor()) { if (that.isConstructor()) { return this == that; } return false; } if (this.isInterface()) { if (that.isInterface()) { return this.getReferenceName().equals(that.getReferenceName()); } return false; } if (that.isInterface()) { return false; } return this.typeOfThis.equals(that.typeOfThis) && this.call.equals(that.call); } @Override public int hashCode() { return isInterface() ? getReferenceName().hashCode() : call.hashCode(); } public boolean hasEqualCallType(FunctionType otherType) { return this.call.equals(otherType.call); } /** * Informally, a function is represented by * {@code function (params): returnType} where the {@code params} is a comma * separated list of types, the first one being a special * {@code this:T} if the function expects a known type for {@code this}. */ @Override public String toString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return "Function"; } StringBuilder b =

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS> new StringBuilder(32); b.append("function ("); int paramNum = (call == null || call.parameters == null) ? 0 : call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { b.append("this:"); b.append(typeOfThis.toString()); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); while (p != null) { b.append(", "); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); } } b.append(")"); if (call != null && call.returnType != null) { b.append(": "); b.append(call.returnType); } return b.toString(); } /** Gets the string representation of a var args param. */ private void appendVarArgsString(StringBuilder builder, JSType paramType) { if (paramType.isUnionType()) { // Remove the optionalness from the var arg. paramType = ((UnionType) paramType).getRestrictedUnion( registry.getNativeType(JSTypeNative.VOID_TYPE)); } builder.append("...[").append(paramType.toString()).append("]"); } /** * A function is a subtype of another if their call methods are related via * subtyping and {@code this} is a subtype of {@code that} with regard to * the prototype chain. */ @Override public boolean isSubtype(JSType that) { if (this.equals(that)) { return true; } if (that.isFunctionType()) { if (((FunctionType) that).isInterface()) { // Any function can be assigned to an interface function. return true; } if (this

Closure, 103

<FILEB>
<CHANGES>
case Token.INSTANCEOF:
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (foundType == null) {
ObjectType maybeType = ObjectType.cast(
registry.getGreatestSubtypeWithProperty(type, field));
<CHANGEE>
<CHANGES>
if (maybeType!= null && maybeType.hasOwnProperty(field)) {
foundType = maybeType;
}
}
<CHANGEE>
<FILEE>
<FILEB> } target = target.getParent(); } return false; } /** * Determines if the subtree might throw an exception. */ private static boolean mayThrowException(Node n) { switch (n.getType()) { case Token.CALL: case Token.GETPROP: case Token.GETELEM: case Token.THROW: case Token.NEW: case Token.ASSIGN: case Token.INC: case Token.DEC: <CHANGES> <CHANGEE> return true; case Token.FUNCTION: return false; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) { return true; } } return false; } /** <FILEE> <FILEB> } // Ignore the prototype itself at all times. if ("prototype".equals(field)) { return null; } // We look up the prototype chain to find the highest place (if any) that // this appears. This will make references to overriden properties look // like references to the initial property, so they are renamed alike. ObjectType foundType = null; ObjectType objType = ObjectType.cast(type); while (objType != null && objType.getImplicitPrototype() != objType) { if (objType.hasOwnProperty(field)) { foundType = objType; } objType = objType.getImplicitPrototype(); } // If the property does not exist on the referenced type but the original // type is an object type, see if any subtype has the property. <CHANGES> <CHANGEE> // getGreatestSubtypeWithProperty does not guarantee that the property // is defined on the returned type, it just indicates that it might be, // so we have to double check. <CHANGES> <CHANGEE> return foundType; } @Override public JSType getInstanceFromPrototype(JSType type) { if (type.isFunctionPrototypeType()) { FunctionPrototypeType prototype = (FunctionPrototypeType) type; FunctionType owner = prototype.getOwnerFunction(); if (owner.isConstructor() || owner.isInterface()) { return ((FunctionPrototypeType) type).getOwnerFunction() .getInstanceType(); } } return null;<SCANS>.isInterface()) { // An interface function cannot be assigned to anything. return false; } // If functionA is a subtype of functionB, then their "this" types // should be contravariant. However, this causes problems because // of the way we enforce overrides. Because function(this:SubFoo) // is not a subtype of function(this:Foo), our override check treats // this as an error. It also screws up out standard method // for aliasing constructors. Let's punt on all this for now. // TODO(nicksantos): fix this. FunctionType other = (FunctionType) that; return (this.isConstructor() || other.isConstructor() || other.typeOfThis.isSubtype(this.typeOfThis) || this.typeOfThis.isSubtype(other.typeOfThis)) && this.call.isSubtype(other.call); } if (that instanceof UnionType) { UnionType union = (UnionType) that; for (JSType element : union.alternates) { if (this.isSubtype(element)) { return true; } } } return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseFunctionType(this); } /** * Gets the type of instance of this function. * @throws IllegalStateException if this function is not a constructor * (see {@link #isConstructor()}). */ public ObjectType getInstanceType() { Preconditions.checkState(hasInstanceType()); return typeOfThis; } /** Sets the instance type. This should only be used for special native types. */ void setInstanceType(ObjectType instanceType) { typeOfThis = instanceType; } /** * Returns whether this function type has an instance type. */ public boolean hasInstanceType() { return isConstructor() || isInterface(); } /** * Gets the type of {@code this} in this function. */ public ObjectType getTypeOfThis() { return typeOfThis.isNoObjectType() ? registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis; } /**